目录

同一、方案架构

  1. ASP.NET
    MVC搭建筑类后台UI框架—1、后台主框架
  2. ASP.NET
    MVC搭建筑类后台UI框架—2、菜单特效
  3. ASP.NET
    MVC搭建筑项目后台UI框架—3、面板折叠和展开
  4. ASP.NET
    MVC搭建筑类后台UI框架—4、tab多页签支持
  5. ASP.NET
    MVC搭建筑类后台UI框架—5、Demo演示Controller和View的竞相
  6. ASP.NET
    MVC搭建筑类后台UI框架—6、客户保管(添加、修改、查询、分页)
  7. ASP.NET
    MVC搭建筑项目后台UI框架—7、统计报表
  8. ASP.NET
    MVC搭建筑项目后台UI框架—8、将View中摘的数据行中的一些数据传到Controller中
  9. ASP.NET
    MVC搭建筑项目后台UI框架—9、服务器端排序

  本方案架构很简短——它之所以一个Web服务来包装ASP.NET
2.0提供者并且也远程客户暴露该证据管理,你还还能以该架构中加上有的去的意义。然后,在提供一个增长的用户接口及全面凭证管理更的同时,使用一个Windows表单应用程序来花费该Web服务。该Web服务配置文件拿包含特定于该证据存储的命令。然而,这确实意味着有由该Web服务管理之应用程序都将可共享这些指令。

进而之前不写了的接轨,本篇,我将执教在是UI框架中同ASP.NET
MVC4进行组合开发。效果如下:

  尽管你会起到尾地构建该Web服务,也就是说,首先用静态方法Roles和Membership来包装它们并定义该Web服务,我倒是再也欣赏同种契约驱动的措施:首先设计执行各种操作的绝好接口将凡什么,并且直到需要时才考虑什么实现它。这样做足保证由Web服务暴露的接口支持有要求的军事管制力量并且还用回落该客户应用程序与其它实现细节(例如包装提供者)之间的耦合。

统计 1统计 2统计 3

   ASP.NET
2.0底一个又好之性状是它支持Web服务接口,你得定义并且让该Web服务暴露逻辑接口,就象类的表现一致。为之,你用因此
WebServiceBinding属性修饰你的接口并且经过WebMethod属性来暴露单个的接口方法。然后,你拿发生一个派生于这个接口的近乎并促成该接口,而且编译器将要求而支持该接口的持有办法。

这里,我以助长和改动用了少数只例外的视图,当然为足以拿长和修改放到跟一个视图中,但是要是描绘有事情逻辑代码来区别当前调用的凡修改还是长,根据添加及改动的差,而针对性界面进行不同的操作。

  为了管住与相互于凭证存储和Web服务配置,我定义了5单接口-IApplicationManager,IMembershipManager,IPasswordManager,IroleManager和IUserManager。

补给加控制器Customer,关于创新操作,我就是不得不怀念吐槽一下NHibernate,他妹的,每次都使先load一次于,然后还Update()一坏,如果您一直save,它就是将您发明中来,但是界面上从来不污染过来的值周更新为null了,相比之下EF就哼多矣。

  (一) IApplicationManager

统计 4统计 5

  该IApplicationManager接口显示为所附源码中之列表2,允许管理员删除一点名的应用程序-也就是说,从数据库中除去所有到它们的参照并且删除其的有所用户以及角色。IApplicationManager允许从存储着删除所有的应用程序,并且它们亦可回去在该存储着的有应用程序的一个列表。注意,这个接口作为一个里边的接口被定义-public或internal可见性修饰词对Web服务接口都是空泛的。该接口及之每个方法用
WebMethod属性加以修饰并出一个拖欠办法的简易描述。此外,存取凭证存储的备方还叫安装也运用事务处理。这样吧,两栽操作-如剔除一使用程序和创建同用户用以相互了割裂的情况下实施,从而确保了一旦剔除所有用户等复杂操作的原子性。.NET
2.0饱受之Web服务只能启动一个初工作,而且它是由于WebMethod属性的TransactionOption属性来决定的。最后一点凡管
WebServiceBinding属性应用为接口及。这就指定该接口是一个客户与服务还能够绑定到的Web服务接口。为了拿该接口以一个WSDL契约方式暴露被外界,你得采取一个shim类。这个shim类的统筹是少不了的,因为你不能够将一个接口作为一Web服务暴露,而且你为无可知以该及采取
WebService属性。这个shim类还以经WebService属性为该接口命名空间定义。下面的代码显示了
IApplicationManagerShim抽象类的定义。

 public class CustomerController : Controller
    {
 private string message = "<script>frameElement.api.opener.hidePublishWin('{0}', '{1}','{2}'); </script>"; //消息,是否关闭弹出窗,是否停留在当前分页(0,1)

        #region 客户管理主页
        public ActionResult Index()
        {
            return View();
        }

        /// <summary>
        /// 客户列表
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        [HttpPost]
        public JsonResult List(CustomerFilter filter)
        {
            filter.PageSize = int.MaxValue;
            var dataSource = CustomerInfo.GetByFilter(filter);

            List<CustomerInfo> queryData = dataSource.ToList();

            var data = queryData.Select(u => new
            {
                ID = u.ID,
                CusCode = u.CusCode,
                CusName = u.CusName,
                BusssinessType = u.BusssinessType.GetDescription(false),
                Balance = u.Balance,
                CreditAmount = u.CreditAmount,
                Status = u.Status.GetDescription(false),
                Country = u.Country,
                CompanyName = u.CompanyName,
                Delivery = GetDeliveryList(u.ExpressCurInfoBy)

            });

            //构造成Json的格式传递
            var result = new { iTotalRecords = queryData.Count, iTotalDisplayRecords = 10, data = data };
            return Json(result, JsonRequestBehavior.AllowGet);
        }
        #region 添加客户
        /// <summary>
        /// 添加客户
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ActionResult AddCustomer()
        {
            ViewBag.Title = "添加客户";
            return View();
        }

        /// <summary>
        /// 添加客户
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        [HttpPost]
        public ActionResult AddCustomer(CustomerInfo info)
        {
            string msg = string.Empty;
            if (ModelState.IsValid)
            {
                try
                {
                    info.Save();
                    msg = "添加客户成功。";
                }
                catch (Exception ex)
                {
                    msg = "添加客户失败!" + ex.Message;
                    ViewBag.Msg = string.Format(message, msg, false,"0");
                }
                ViewBag.Msg = string.Format(message, msg, true,"0");
            }
            return View();
        }
        #endregion

        #region 修改客户
        /// <summary>
        /// 修改客户
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ActionResult UpdateCustomer(int id)
        {
            ViewBag.Title = "修改客户";
            var result = CustomerInfo.Load(id);

            return View(result);
        }

        /// <summary>
        /// 修改客户
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        [HttpPost]
        public ActionResult UpdateCustomer(CustomerInfo info)
        {
            string msg = string.Empty;
            if (ModelState.IsValid)
            {
                try
                {
                    info.Update();
                    msg = "修改客户成功。";
                }
                catch (Exception ex)
                {
                    msg = "修改客户失败!" + ex.Message;
                    ViewBag.Msg = string.Format(message, msg, false,"1");
                }
                ViewBag.Msg = string.Format(message, msg, true,"1");
            }
            return View();
        }
        #endregion
    }

[WebService(Name=”IApplicationManager”,
Namespace=”http://CredentialsServices”,
Description=”IApplicationManager is used to manage
applications. This web service is only
the definition of the interface. You
cannot invoke method calls on it.”)]
abstract class IApplicationManagerShim : IApplicationManager{
 public abstract void DeleteApplication(string application);
 public abstract string[] GetApplications();
 public abstract void DeleteAllApplications();
}

View Code

  因为IApplicationManagerShim是一个类似,所以您得拿它们暴露吗一个Web服务。因为它是平虚幻类都持有方吃定义为架空方法,所以未待(也未可知)实现其他方法。为了要其扣留起就象该接口,IapplicationManagerShim把WebService属性的特性名设置为
IApplicationManager(代替缺省之类名)。现在,你可以运用IApplicationManager.asmx文件来暴露该接口。

补偿加视图Index

<%@ WebService Language=”C#”
CodeBehind=”~/App_Code/IApplicationManagerShim.cs”
Class=”IApplicationManagerShim”%>

统计 6统计 7

  现在,如果您浏览到IApplicationManager.asmx页面,你虽见面看该接口定义。你可以使WSDL.exe的serverInterface选项来管接口定义输入到客户端或其它其它想绑定到该接口定义上的劳动。

@{
    ViewBag.Title = "客户信息";
}
<link href="~/libs/DataTables-1.10.6/media/css/jquery.dataTablesNew.css" rel="stylesheet" />
<script src="~/libs/DataTables-1.10.6/media/js/jquery.dataTables.min.js"></script>
<script src="~/Scripts/DataTablesExt.js"></script>
<script type="text/javascript">
    //弹出框  
    var addDG, updateDG, matchDG;
    var w = 424, h = 520; //宽,高
    //添加记录
    function showPublishWin() {
        addDG = new $.dialog({
            id: "AddChannel",
            title: "添加客户",
            content: "url:/Customer/AddCustomer",
            width: w,
            height: h,
            max: false,
            min: false,
            lock: true,
            close: true,
            btnBar: false
        });
        addDG.show();
    }
    //修改记录
    function modifyRecord(id) {
        updateDG = new $.dialog({
            id: "UpdateCustomer",
            title: "修改客户",
            content: "url:/Customer/UpdateCustomer/" + id,
            width: w,
            height: h,
            max: false,
            min: false,
            lock: true,
            close: true,
            btnBar: false
        });
        updateDG.show();
    }
    //隐藏弹出框
    function hidePublishWin(msg, result, isStay) {
        var icon = "success.gif";
        if (result == "False") {
            icon = "error.gif";
        }
        $.dialog({
            title: "提示",
            icon: icon,
            titleIcon: 'lhgcore.gif',
            content: msg,
            lock: true,
            ok: true
        });
        if (result != "False") {
            if (addDG) {
                addDG.close();
            }
            if (updateDG) {
                updateDG.close();
            }
            if (matchDG) {
                matchDG.close();
            }
            if (isStay == 0) {
                reloadList();
            }
            else {
                reloadListNew();
            }
        }
    }
    function matchDelivery(id) {
        matchDG = new $.dialog({
            id: "UpdateCustomer",
            title: "客户匹配",
            content: "url:/Customer/DeliveryMatching/" + id,
            width: 800,
            height: h,
            max: false,
            min: false,
            lock: true,
            close: true,
            btnBar: false
        });
        matchDG.show();
    }
    //刷新,但是停留在当前分页
    function reloadListNew() {
        var tables = $('#table_local').dataTable().api();//获取DataTables的Api,详见 http://www.datatables.net/reference/api/
        tables.ajax.reload(null,false);
    }
</script>
<script type="text/javascript">
    $(function () {
        var h = $(document).height() - 258;
        var table = $("#table_local").dataTable({
            bProcessing: true,
            "scrollY": h,
            "scrollCollapse": "true",
            "dom": 'ftr<"bottom"lip><"clear">',
            "bServerSide": false,                    //指定从服务器端获取数据  
            sServerMethod: "POST",
            sAjaxSource: "@Url.Action("List", "Customer")",
            "fnServerParams": function (aoData) {  //查询条件
                aoData.push(
                    { "name": "CusCode", "value": $("#CusCode").val() },
                    { "name": "CusName", "value": $("#CusName").val() }
                    );
            },
            columns: [{ title: "1", "visible": false, "data": "ID" },
               { "data": "CusCode", title: "客户代码" },
               { "data": "CusName", title: "客户名称" },
               { "data": "BusssinessType", title: "业务类型", width: "100" },
               { "data": "Country", title: "国家", width: "200" },
               { "data": "CompanyName", title: "公司名称", width: "200" },
               { "data": "Delivery", title: "收货商", width: "150" },
               { "data": "Balance", title: "账户余额", width: "150" },
               { "data": "CreditAmount", title: "信用额度", width: "150" },
               { "data": "Status", title: "是否启用", width: "100" },
               {
                   "data": "ID", orderable: false, title: "操作", width: "140", "render": function (data, type, row, meta) { //自定义列
                       var re = "<div style='text-align:center'><a style='visibility:visible' onclick='modifyRecord(" + data + ")'>修改</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
                       re = re + "<a style='visibility:visible' onclick='matchDelivery(" + data + ")'>匹配</a></div>";
                       return re;
                   }
               }
            ],
            paging: true,//分页
            ordering: true,//是否启用排序
            searching: true,//搜索
            language: {
                "sProcessing": "处理中...",
                lengthMenu: '每页显示:<select class="form-control input-xsmall">' + '<option value="5">5</option>' + '<option value="10">10</option>' + '<option value="15">15</option>'
                    + '<option value="20">20</option>' + '<option value="25">25</option>' + '<option value="30">30</option>' + '<option value="35">35</option>' + '<option value="40">40</option>',//左上角的分页大小显示。
                search: '搜索:',//右上角的搜索文本,可以写html标签

                paginate: {//分页的样式内容。
                    previous: "上一页",
                    next: "下一页",
                    first: "",
                    last: ""
                },

                zeroRecords: "暂无记录",//table tbody内容为空时,tbody的内容。
                //下面三者构成了总体的左下角的内容。
                info: "总共 (_PAGES_) 页,显示 _START_ -- _END_ ,共 (_TOTAL_) 条",//左下角的信息显示,大写的词为关键字。初始_MAX_ 条 
                infoEmpty: "0条记录",//筛选为空时左下角的显示。
                infoFiltered: ""//筛选之后的左下角筛选提示,
            },
            pagingType: "full_numbers"//分页样式的类型

        });
        //设置选中行样式
        $('#table_local tbody').on('click', 'tr', function () {
            if ($(this).hasClass('selected')) {
                $(this).removeClass('selected');
            }
            else {
                table.$('tr.selected').removeClass('selected');
                $(this).addClass('selected');
            }
        });
    });
    //查询 刷新
    function reloadList() {
        var tables = $('#table_local').dataTable().api();//获取DataTables的Api,详见 http://www.datatables.net/reference/api/
        tables.ajax.reload();
    }
</script>
<div class="areabx clear">
    @using (Html.BeginForm("List", null, FormMethod.Get, new { @clase = "form-inline", @role = "form" }))
    {
        <div class="areabx_header">客户信息</div>
        <ul class="formod mgt10">
            <li>客户代码:@Html.TextBox("CusCode", "", new { @class = "trade-time wid153" })</li>
            <li>客户名称:@Html.TextBox("CusName", "", new { @class = "trade-time" })</li>
            <li></li>
        </ul>
        <div class="botbtbx pdb0" style="margin-bottom: -30px;">
            <input type="button" value="添加客户" class="btn btn-primary" onclick="showPublishWin()" />
            <input type="button" value="查询" onclick="reloadList();" class="btn btn-primary">
        </div>
    }
    <div class="tob_box mgt15">
        <table id="table_local" class="display" cellspacing="0" cellpadding="0" border="0" style="width: 100%">
        </table>
    </div>
</div>

  (二) IMembershipManager

View Code

  IMembershipManager接口(见所附源码中之列表3)允许而管理用户帐户的有地方-创建同去用户帐户,更新用户帐户,检索用户帐户细节和查找在同样施用程序中之所有用户。

添加AddCustomer视图,之前公司ASP.NET
MVC的花色并未启用模型验证,界面验证代码都是协调js写的,我晕,那用ASP.NET
MVC干嘛呢?使用框架就是使充分发挥框架优良的职能,尽可能快便捷的开支,并缩减开发人员的代码量。

  (三) IRoleManager

统计 8统计 9

  IRoleManager接口允许而管理逻辑角色的拥有地方-创建和去角色,从角色遭多与去用户和查找在同样施用程序中的享有角色。

@model Core.Customer.CustomerInfo
@using ProjectBase.Utils
@Html.Raw(ViewBag.Msg)
<div class="areabx clear">
@*    <div class="areabx_header">@ViewBag.Title</div>*@
    <div class="tian_xi">
        @using (Html.BeginForm("AddCustomer", "Customer", FormMethod.Post, new { @clase = "form-inline", @role = "form", name = "from1" }))
        {
            <table width="100%" border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr style="height: 40px;">
                        <td style="width: 120px; text-align: right;">客户代码:</td>
                        <td>
                            @Html.TextBoxFor(x => x.CusCode, new { @class = "trade-timen", @id = "cusCode" })* @Html.ValidationMessageFor(m => m.CusCode)</td>
                    </tr>
                    <tr style="height: 40px;">
                        <td align="right">客户名称:</td>
                        <td>
                            @Html.TextBoxFor(x => x.CusName, new { @class = "trade-timen", @id = "cusName" })* @Html.ValidationMessageFor(m => m.CusName)</td>
                    </tr>
                    <tr style="height: 40px;">
                        <td align="right">手机:</td>
                        <td>
                            @Html.TextBoxFor(x => x.Phone, new { @class = "trade-timen" })</td>
                    </tr>
                    <tr style="height: 40px;">
                        <td align="right">电话:</td>
                        <td>
                            @Html.TextBoxFor(x => x.Tel, new { @class = "trade-timen" })</td>
                    </tr>
                    <tr style="height: 40px;">
                        <td align="right">邮箱:</td>
                        <td>
                            @Html.TextBoxFor(x => x.Email, new { @class = "trade-timen", @id = "email" })@Html.ValidationMessageFor(m => m.Email)</td>
                    </tr>
                    <tr style="height: 40px;">
                        <td align="right">传真:</td>
                        <td>
                            @Html.TextBoxFor(x => x.Fax, new { @class = "trade-timen" })</td>
                    </tr>
                    <tr style="height: 40px;">
                        <td align="right">国家:</td>
                        <td>
                            @Html.TextBoxFor(x => x.Country, new { @class = "trade-timen" })</td>
                    </tr>
                    <tr style="height: 40px;">
                        <td align="right">地址:</td>
                        <td>
                            @Html.TextBoxFor(x => x.Address, new { @class = "trade-timen" })</td>
                    </tr>
                    <tr style="height: 40px;">
                        <td align="right">公司名称:</td>
                        <td>
                            @Html.TextBoxFor(x => x.CompanyName, new { @class = "trade-timen" })</td>
                    </tr>
                    <tr style="height: 40px;">
                        <td align="right">业务类型:</td>
                        <td>
                        @Html.DropDownListFor(x => x.BusssinessType, @Html.EnumToList(typeof(Core.Customer.Busssiness), false), new { @class = "trade-timen", style = "width:180px" })
                    </tr>
                    <tr style="height: 40px;">
                        <td align="right">是否启用:</td>
                        <td>是 @Html.RadioButtonFor(x => x.Status, "0", new { Checked = "checked", @name = "status" }) &nbsp;&nbsp;&nbsp;&nbsp;
                            否 @Html.RadioButtonFor(x => x.Status, "1", new { @name = "status" })</td>
                    </tr>
                </tbody>
            </table>
            <input type="submit" value="确定" class="popbtn1 mg">
            <input type="button" value="关闭" class="popbtn3 mg2" onclick="frameElement.api.opener.addDG.close();" />
        }
    </div>
</div>

[WebServiceBinding(“IRoleManager”)]
interface IRoleManager{
[WebMethod(…)]
void CreateRole(string application,string role);
[WebMethod(…)]
bool DeleteRole(string application,string role,bool
throwOnPopulatedRole);
[WebMethod(…)]
void AddUserToRole(string application,string userName, string role);
[WebMethod(…)]
void DeleteAllRoles(string application,bool throwOnPopulatedRole);
[WebMethod(…)]
string[] GetAllRoles(string application);
[WebMethod(…)]
string[] GetRolesForUser(string application,string userName);
[WebMethod(…)]
string[] GetUsersInRole(string application, string role);
[WebMethod(…)]
void RemoveUserFromRole(string application,string userName, string
roleName);
//更多成员
}

View Code

  (四) IPasswordManager

添加UpdateCustomer视图

  这个IPasswordManager接口主要提供与应用程序口令策略相关的才读信息。

统计 10统计 11

[WebServiceBinding(“IPasswordManager”)]
interface IPasswordManager{
[WebMethod(…)]
bool EnablePasswordReset(string application);
[WebMethod(…)]
bool EnablePasswordRetrieval(string application);
[WebMethod(…)]
string GeneratePassword(string application,int length,
int numberOfNonAlphanumericCharacters);
[WebMethod(…)]
bool RequiresQuestionAndAnswer(string application);
[WebMethod(…)]
string ResetPassword(string application,string userName);
[WebMethod(…)]
string GetPassword(string application,string userName,string
passwordAnswer);
[WebMethod(…)]
void ChangePassword(string application,string userName,string
newPassword);
//更多成员
}

@model Core.Customer.CustomerInfo
@using ProjectBase.Utils
@Html.Raw(ViewBag.Msg)
<div class="areabx clear">
@*    <div class="areabx_header">@ViewBag.Title</div>*@
    <div class="tian_xi">
        @using (Html.BeginForm("UpdateCustomer", "Customer", FormMethod.Post, new { @clase = "form-inline", @role = "form", name = "from1" }))
        {
            <table width="100%" border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr style="height: 40px;">
                        <td style="width: 120px; text-align: right;">客户代码:</td>
                        <td>
                            @Html.TextBoxFor(x => x.CusCode, new { @class = "trade-timen", @id = "cusCode", @readOnly = "readOnly" })* @Html.ValidationMessageFor(m => m.CusCode)</td>
                        @Html.HiddenFor(x => x.ID)
                    </tr>
                    <tr style="height: 40px;">
                        <td align="right">客户名称:</td>
                        <td>
                            @Html.TextBoxFor(x => x.CusName, new { @class = "trade-timen", @id = "cusName" })* @Html.ValidationMessageFor(m => m.CusName)</td>
                    </tr>
                    <tr style="height: 40px;">
                        <td align="right">手机:</td>
                        <td>
                            @Html.TextBoxFor(x => x.Phone, new { @class = "trade-timen" })</td>
                    </tr>
                    <tr style="height: 40px;">
                        <td align="right">电话:</td>
                        <td>
                            @Html.TextBoxFor(x => x.Tel, new { @class = "trade-timen" })</td>
                    </tr>
                    <tr style="height: 40px;">
                        <td align="right">邮箱:</td>
                        <td>
                            @Html.TextBoxFor(x => x.Email, new { @class = "trade-timen", @id = "email" }) @Html.ValidationMessageFor(m => m.Email)</td>
                    </tr>
                    <tr style="height: 40px;">
                        <td align="right">传真:</td>
                        <td>
                            @Html.TextBoxFor(x => x.Fax, new { @class = "trade-timen" })</td>
                    </tr>
                    <tr style="height: 40px;">
                        <td align="right">国家:</td>
                        <td>
                            @Html.TextBoxFor(x => x.Country, new { @class = "trade-timen" })</td>
                    </tr>
                    <tr style="height: 40px;">
                        <td align="right">地址:</td>
                        <td>
                            @Html.TextBoxFor(x => x.Address, new { @class = "trade-timen" })</td>
                    </tr>
                    <tr style="height: 40px;">
                        <td align="right">公司名称:</td>
                        <td>
                            @Html.TextBoxFor(x => x.CompanyName, new { @class = "trade-timen" })</td>
                    </tr>
                    <tr style="height: 40px;">
                        <td align="right">业务类型:</td>
                        <td>
                        @Html.DropDownListFor(x => x.BusssinessType, @Html.EnumToList(typeof(Core.Customer.Busssiness), false), new { @class = "trade-timen", style = "width:180px" })
                    </tr>
                    <tr style="height: 40px;">
                        <td align="right">是否启用:</td>
                        <td>是 @Html.RadioButtonFor(x => x.Status, "0", new { Checked = "checked", @name = "status" }) &nbsp;&nbsp;&nbsp;&nbsp;
                            否 @Html.RadioButtonFor(x => x.Status, "1", new { @name = "status" })</td>
                    </tr>
                </tbody>
            </table>
            <input type="submit" value="确定" class="popbtn1 mg">
            <input type="button" value="关闭" class="popbtn3 mg2" onclick="frameElement.api.opener.updateDG.close();" />
        }
    </div>
</div>

  典型地,该政策存储于应用程序的安排文件中。该方针包括是否启动口令重置和查找,口令强度及口令回答策略等。你为堪下
IpasswordManager来生成一对应被该口令强度策略的初口令。另外,IpasswordManager可用于重置、改变或者找一指定用户之口令。

View Code

  (五) IUserManager

客户实体CustomerInfo

  IUserManager接口允许校验用户凭证,检索角色地位跟取得指定用户是其成员之一之有所角色。该接口用于测试和剖析目的。

统计 12统计 13

[WebServiceBinding(“IUserManager”)]
public interface IUserManager{
[WebMethod(…)]
bool Authenticate(string applicationName,string userName, string
password);
[WebMethod(…)]
bool IsInRole(string applicationName,string userName, string role);
[WebMethod(…)]
string[] GetRoles(string applicationName,string userName);
}
二、AspNetSqlProviderService Web服务

    /// <summary>
    /// 客户信息
    /// </summary>
    public class CustomerInfo //: DomainObject<CustomerInfo, int, ICustomerInfoRepository>
    {
        #region property
        /// <summary>
        /// 客户代码
        /// </summary>
        [Required(ErrorMessage = "客户代码不能为空!")]
        [StringLength(30, MinimumLength = 0, ErrorMessage = "客户代码最大长度为30个字符")]
        public virtual string CusCode { get; set; }
        /// <summary>
        /// 客户名称
        /// </summary>
        [Required(ErrorMessage = "客户名称不能为空!")]
        [StringLength(30, MinimumLength = 0, ErrorMessage = "客户名称最大长度为30个字符")]
        public virtual string CusName { get; set; }
        /// <summary>
        /// 客户业务类型
        /// </summary>
        public virtual Busssiness BusssinessType { get; set; }
        /// <summary>
        /// 手机
        /// </summary>
        public virtual string Phone { get; set; }
        /// <summary>
        /// 电话
        /// </summary>
        public virtual string Tel { get; set; }
        /// <summary>
        /// 邮箱
        /// </summary>
        [RegularExpression(@"^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$", ErrorMessage="邮箱格式不正确!")]
        public virtual string Email { get; set; }
        /// <summary>
        /// 传真
        /// </summary>
        public virtual string Fax { get; set; }
        /// <summary>
        /// 国家
        /// </summary>
        public virtual string Country { get; set; }
        /// <summary>
        /// 地址
        /// </summary>
        public virtual string Address { get; set; }
        /// <summary>
        /// 公司名称
        /// </summary>
        public virtual string CompanyName { get; set; }
        /// <summary>
        /// 金额
        /// </summary>
        public virtual decimal Balance { get; set; }
        /// <summary>
        /// 信用额度
        /// </summary>
        public virtual decimal CreditAmount { get; set; }
        /// <summary>
        /// 状态
        /// </summary>
        public virtual CustomerStatus Status { get; set; }
        /// <summary>
        /// 快件收货商信息
        /// </summary>
        public virtual IList<ExpressCurInfo> ExpressCurInfoBy { get; set; }
        #endregion

        #region common method
        /// <summary>
        /// 分页获取数据
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        public static IPageOfList<CustomerInfo> GetByFilter(CustomerFilter filter)
        {
            return Dao.GetByFilter(filter);
        }
        #endregion
    }

  显示在所附源码中的列表4蒙受之
AspNetSqlProviderService类实现了五独Web接口。其过程就象实现其他其他接口一样-你可以隐式或显式地派生并实现方式(见列表
4)。我是通过将这些实现简单地代理及提供者的适龄的方来贯彻该Web接口上的绝大多数计的。在列一样坏以角色还是位置之前,你必须为之作好准备-通过安装要使用的应用程序名。例如,为了落实IRoleManager.CreateRole(),你用用建立:

View Code

void IRoleManager.CreateRole(string application,string role){
Roles.ApplicationName = application;
Roles.CreateRole(role);
}

查询类CustomerFilter

  其中的一些法在调用该提供者前后还求一点行事。例如,如果开行口令检索,你不得不找用户口令,而AspNetSqlProviderService则用来判定它。

统计 14统计 15

string IPasswordManager.GetPassword(string application,string
userName,
string passwordAnswer){
Membership.ApplicationName = application;
Debug.Assert(Membership.EnablePasswordRetrieval);
MembershipUser membershipUser =Membership.GetUser(userName);
return membershipUser.GetPassword(passwordAnswer);
}

    public class CustomerFilter : ParameterFilter
    {
        /// <summary>
        /// 客户代码
        /// </summary>
        public virtual string CusCode { get; set; }
        /// <summary>
        /// 客户名称
        /// </summary>
        public virtual string CusName { get; set; }

        /// <summary>
        /// 生产NHQL查询语句
        /// </summary>
        /// <returns></returns>
        public override string ToHql()
        {
            string hql = "";
            if (!string.IsNullOrEmpty(CusCode))
            {
                hql += " and Cus_Code =:CusCode ";
            }
            if (!string.IsNullOrEmpty(CusName))
            {
                hql += " and Cus_Name =:CusName ";
            }

            return hql;
        }

        /// <summary>
        /// 构造查询参数
        /// </summary>
        /// <returns></returns>
        public override Dictionary<string, object> GetParameters()
        {
            var result = new Dictionary<string, object>();
            if (!string.IsNullOrEmpty(CusCode))
            {
                result["CusCode"] = CusCode.Trim();
            }
            if (!string.IsNullOrEmpty(CusName))
            {
                result["CusName"] = CusName.Trim();
            }
            return result;
        }
    }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ProjectBase.Utils.Entities;

namespace ProjectBase.Data
{
    public abstract class ParameterFilter
    {
        public ParameterFilter()
        {
            HasQueryString = false;
            PageSize = 10;
        }

        public string OrderBy { get;set; }

        public abstract string ToHql();

        public override string ToString()
        {
            return ToHql();
        }

        public abstract Dictionary<string, object> GetParameters();

        public string GetOrderString()
        {
            if (OrderBy.HasValue())
                return " Order By " + OrderBy;
            return String.Empty;
        }

        protected string GetLike(string value)
        {
            return "%" + value + "%";
        }

        public int PageIndex { get; set; }

        public int PageSize { get; set; }

        /// <summary>
        /// 标识此构造器是包含全部查询语句。
        /// 若为 False,则ToHql() 只需要构造条件查询,系统会自动在前面加上<code>" from " + typeof(T).Name + " a where 1=1 "</code>
        /// 若为 True, ToHql() 需要返回 连form在类的完整Hql语句
        /// </summary>
        public bool HasQueryString { get; set; }

        protected static bool HasValue(string str)
        {
            return str.HasValue();
        }

        public static bool HasValue<T>(System.Nullable<T> value) where T:struct
        {
            return value.HasValue;
        }       

    }
}

  然而,还有部分方法并无获得提供者的直支持。有一定量种植可能的解决办法-第一种是品并应用提供者的其余方法来就所期之操作。第二栽是直实施
aspnetdb数据库。两种艺术还留存利弊。例如,可以设想实现MembershipManager.DeleteAllUsers()方法。你得本着该应用程序中之每个用户调用身份提供者的DeleteUser()方法,如列表4所著。首先你若调用
IMembershipManager.GetAllUsers()方法来收获应用程序中的所有用户。这便是若通过落实该接口的切近来使用该接口方法的显式实现方式。然后,你可以定义一个匿名方式来删除用户,把该匿名方式赋值到一个Action<string>代理,并且使Array类的静态方法
ForEach<T>()删除每个用户。

View Code

public delegate void Action<T>(T obj);
public abstract class Array : …
{
public static void ForEach<T>(T[] array,Action<T> action);
}

每当这边,我特演示了控制器和视图的互,至于Hhibernate和Unity等数据的操作,这里少无开口,因为您吧足以利用其它的ORM框架和IOC框架,诸如EF、AutoFac等等。这里最主要教学jquery
datatables和ASP.NET
MVC的结缘使用,但是此间仅演示了客户端分页排序,后面我会说服务器分页排序。我意识,网上都没ASP.NET
MVC和Datatables结合的完全的服务器分页、排序的Demo,只望PHP的。于是自己不断的品味,皇天不负有心人,终于试验成功了,后面我会为大家讲述实现方式。

  第一种艺术的长是别与删除一个用户相关的内部活动(如为抹所有的角色身份)仍旧为实践。其不足是,你用针对该数据库做还多的调用。

  正使刚刚提到的,第二栽方法是直接针对aspnetdb数据库编程。当提供者没有提供其他措施来完成这任务时,这是最好得力的。例如,提供者并无支持删除一采取程序,更非说去所有的应用程序了。尽管你可以编制一个储存过程来开就起业务,但自之另一个靶是免下aspnetdb,而是下原始SQL命令来落实IApplicationManager.DeleteApplication()和
IApplicationManager.DeleteAllApplications()。我一度因此一个AspNetDbTablesAdapter助理类(在这个没有显得)包装了这些命令。直接访问数据库的亮点是若仅仅执行一个发令;不足之处是,如果只要改变数据库模式,你以需要改变而的代码。假定如去所有的用户要同一动程序等操作是相似不干的以超级用户的数量经常坏粗,那么我思最好尽可能让AspNetSqlProviderService使用
ASP.NET 2.0提供者。

  (一) 设置服务

  由AspNetSqlProviderService
Web服务用的Web.Config文件被的安影响其管理之具备应用程序。特别地,如口令策略这样的安装适用于拥有的应用程序。该服务应用默认提供者
(SQL
SERVER),因此如果少省之总是字符串(在文书machine.config中维护)已经足够的话,就非需指定一个提供者甚至一个接连字符串。如果你要一个见仁见智之连字符串,你用包括一个connectionStrings标签(见所附源码中的列表5)。另外,为了采取Roles类,你必须经下列指令来启动基于角色的安康。

<roleManager enabled=”true” />

  (二) 保护服务

  尽管该据由AspNetSqlProviderService
Web服务来管理的应用程序可能是冲互联网要基于内部网之,但是服务本身是被规划由一个大班通过地面内部网来存取的。你当辨证和授权到拖欠服务之调用。另外,你还应通过加密报道来供隐秘服务。这是讲求的,因为该服务而拍卖要用户称与口令等敏感信息。保证机密的最为爱之方法是运用HTTPS。
AspNetSqlProviderService在它的构造器中经过静态VerifySecureConnection()助理方法来开展说明是否以了一个康宁连接。VerifySecureConnection()使用时恳请的IsSecureConnection属性。为了支持支付要欠服务的其他品类的非生产性发布,VerifySecureConnection()方法用Conditional属性加以修饰。只有定义编译符号HTTPS时该措施才会从作用。关于认证该服务之用户,既然Web服务是千篇一律本地内部网服务,那么下Windows认证就未会见发出外不当了。我选择了运用并的
Windows认证-这将省了用户必须明白地登录的劳动。集成的求证的另外一个优点是,它之所以同样栽专利方式来散列化发送过去的凭据。

  为了安排并的Windows认证,转到当IIS下之AspNetSqlProviderService
Web服务性质,选择目录安全选项卡,并且点击”Edit…”按钮。不挑”Anonymous
access”复选框并且保证选中”Integrated Windows
authentication”复选框。AspNetSqlProviderService类被部署为求说明(见列表4)-它采用
PrincipalPermission属性并拿为证明的特性设计为true。

[PrincipalPermission(SecurityAction.Demand,…,Authenticated=true)]

  一旦调用者通过IIS被证明,该服务差省地用于IIS中因安排的身价仍然运行。我眷恋为调用者身份运行该服务。为者,Web.Config文件(见列表5)包含了一个identity标签-它将impersonate属性设置为true。

<identity impersonate=”true”/>

  然后,你要使用SQL
SERVER管理工具来允许Web服务之调用者从aspnetdb数据库中进行读与描写。

  保护该Web服务之其它一个最主要地方是授权。我眷恋使验证只有Windows超级用户组的成员才会存取这无异服务。为者,AspNetSqlProviderService类上之PrincipalPermission属性要求只有超级用户角色的成员才让允许以该服务。

[PrincipalPermission(SecurityAction.Demand,
Role = “Administrators”,…)]

  你可以据此任何其它组(该服务的骨子里用户应是其中的同个)来替换”Administrators”。

  PrincipalPermission属性使用配属于该线程的安康官员(principal)来说明调用者是否确实是点名角色被的一致各。在负让NT组(如超级用户)时,这将强制你利用一个WindowsPrincipal的实例。

public class WindowsPrincipal : IPrincipal{
 public WindowsPrincipal(WindowsIdentity ntIdentity);
 public virtual bool IsInRole(string role);
 //其它成员有
}

  问题在于,为了以Roles类,AspNetSqlProviderService
Web.Config文件要启动基于角色的安全策略。

<roleManager enabled=”true” />

  这倒过来使得ASP.NET
2.0管同例外的principal依附到HttpContext和线程上,当然还有RolePrincipal类。

public sealed class RolePrincipal : IPrincipal{…}

  于NT超级用户角色中试图使用RolePrincipal和过火要求的位置将会见破产,因为她用存取aspnetdb而不是Windows组来索它。为补充这一点,你要手工地交换这些负责人又于历次要时拿WindowsPrincipal的一个实例依附到拖欠线程上。为之,最轻的计是把一个
Global.asax文件上加至拖欠Web服务工程-通过点名在Global.cs文件被的Global类为接近后的代码。

<%@ Application Language=”C#” CodeBehind =”Global.cs” Inherits =
“Global”%>

  这个Global类为应用程序授权请求提供一个电脑。

public class Global : HttpApplication{
 protected void Application_AuthorizeRequest(object sender, EventArgs
e){
  if(HttpContext.Current.User.Identity.IsAuthenticated){
   WindowsIdentity identity = HttpContext.Current.User.Identity as
WindowsIdentity;
   Debug.Assert(identity != null);
   WindowsPrincipal principal;
   principal = new WindowsPrincipal(identity);
   Thread.CurrentPrincipal = principal;
  }
 } 
}

  如果调用者被证实,那么你需要实例化一新的WindowsPrincipal对象又将它们依附于时线程。WindowsPrincipal构造器需要一个WindowsIdentity的实例。幸好,因为拖欠服务着利用Windows集成的证明,在功成名就验证后,与目前HTTP上下文相沟通的地位早已是
WindowsIdentity类型了,因此若可独自获这个实例。
**三、凭证管理器应用程序

**  本文相应的源代码包含了这证管理器应用程序-一个所有丰富的用户接口的Windows表单应用程序,它采用在达标一样步描述的Web服务接口来也其他数据的应用程序管理安全凭证存储。

  该应用程序导入五只Web接口定义,并且她独占地使用那些接口。该应用程序有一个叫AspNetSqlProviderService的Web服务代办类-它用来固定该服务。你用从导入的接口手工地将她上加到该服务达标。

统计 16
图4.Applications选项卡:这个选项卡让你选择而配置的应用程序。

partial class AspNetSqlProviderService :
SoapHttpClientProtocol,IMembershipManager,
IUserManager,IPasswordManager,
IApplicationManager,IRoleManager
{
 public AspNetSqlProviderService (){
  Credentials = CredentialCache.DefaultCredentials;
  Url = Settings.Default.AspNetSqlProviderService ;
 }
 //其它的尽
}

  为了支持并的Windows认证,这个代理类的构造器使用CredentialCache的静态属性DefaultCredentials设置凭证属性-它只是略地朗诵博时线程的安全标志。另外,这个构造器还动用设计器生成的Settings类从应用程序配置类似中读取Web服务地方。

统计 17
图5.Users选项卡:该选项卡列出当选定的应用程序中的备用户。

  这个应用程序的动一定直观,所以我独自介绍一下要屏幕跟选择。Applications选项卡(见图4)允许而拣要安排的应用程序。

  在此,选择同一运程序用影响有其他的精选项卡。你可以创造及去一个应用程序或删除所有应用程序。Users选项卡列举出在挑选的应用程序中的备用户。

  你可创造或者去一用户。如果你剔除一用户可不挑”All
Data”复选框的言语,它用去除该用户可保持其的角色身份信息。你可以更新一用户帐户或删除所有用户。根据从
AspNetSqlProviderService
Web服务返回的口令策略的例外,你会或无克转移或重置口令,而且可要不可以得应对该口令。在Users选项卡的按钮和她所著的对话框也应和地启动或取缔。

  于Users选项卡的右边是统计信息,如当前用户的在线数。Roles选项卡允许你拿角色添加到应用程序。

统计 18
希冀6:Roles选项卡:这个选项卡让你管角色添加到应用程序。

  当去一个角色时,如果你挑了”Fail if
populated”复选框,那么一旦她有其它成员来说,就无见面让你删掉该角色。左边的列表视图显示在该应用程序中的有用户。你可于一个角色添加或删除一用户,或打有角色被剔除一用户。在底部,”Users
in role”列表框显示了在地方选定的角色遭之享有用户,而”Roles for
User”列表框显示了当面选定的用户中之具备角色。

  Passwords选项卡显示在图7中,它列有就布置的口令策略并且同意你特别成一及指定的口令强度策略相兼容的初口令。

统计 19
贪图7.Passwords选项卡:你得用是选项卡生成一人叫。

统计 20
希冀8.Credentials Service选项卡:使用这选项卡来选采取的Web服务。

  该选项卡让你挑选而运的Web服务。一旦启动,凭证管理器应用程序即从应用程序配置文件中读取这个地址。这个选项卡显示为挑的Web服务。如果地方是不行的,也就是说,该服务不支持具有要求的作用,那么以应用程序中之具有控件都以为空且是禁止的。你得供一个见仁见智的地方,而脚的Web浏览器控件将会晤显得这等同劳动。然而,如果该服务支持要求的Web方法(一得力之Web服务)的话,你可以仅挑一个Web服务地方(通过点击Select按钮)。如果该服务是杯水车薪的,那么以禁Select按钮。

  不幸之是,在.NET
2.0吃并未提供校验某服务是否支持一特别绑定或Web接口的坐支持,因此我只好手工实现。所附源码中之列表6显示有
RefreshSelectButton()和ContainsInterface()助理方法。RefreshSelectButton()首先禁止
Select按钮和互相匹配的菜肴单项。然后,验证指定的地址是一个.NET
Web服务的地方。然后,它存取显示在Web浏览器控件被之页面的内容而证实其富含支持所有的接口的办法。为这个,它如果调用
ContainsInterface()方法并将页面的始末以及苟证明的接口类型提供给它。ContainsInterface()验证该种是一个接口的类又获得一个MethodInfo对象数组-标记在拖欠接口及之每个方法。然后,它定义一个接单个实例MethodInfo的匿名方式以以字符串类的Contains()方法来验证该内容涵盖那个方式。ContainsInterface()使用该数组类的静态TrueForAll<T>()方法。

public delegate bool Predicate<T>(T obj);
public abstract class Array : …
{
 public static bool TrueForAll<
 T>(T[] array,Predicate<
 T> match);
}

  ContainsInterface()提供于TrueForAll()一个MethodInfo对象数组和匿名方式形式的Predicate。只有以拖欠内容遭找到有的主意时,TrueForAll<T>()才回到true。
http://www.7dspace.com/doc/24/0512/2005123006395536935_1.htm