• ASP.NET从MVC5升级到MVC6


    1-1)文件结构的升级(Area和Filter知识总结) - ASP.NET从MVC5升级到MVC6

     

    ASP.NET从MVC5升级到MVC6 总目录

    MVC5项目结构

    带有Areas和Filter的项目结构

    一般来说,小的MVC项目是不考虑领域的,但是,如果是稍微复杂一点的项目,往往是需要领域这个概念的。
    一个领域就是一个小型的MVC项目,所以领域Area的目录结构和普通的目录结构是一样的。(具有Controllers和Views目录,以及一个AreaRegistration文件)
    一个MVC项目,Controllers和Views这两个目录由于约定的关系,文件夹的名称和相对位置是不能变化的。
    在默认的配置下,Controllers下面的Controller和Views下面的子文件夹是一一对应的。Controller里面的方法和View下面的CSHTML视图也是一一对应的。
    Model这个文件夹不是必须的,而且按照趋势,Model一般被归为BussinessLogic,往往存在于业务的工程中。数据模型的问题,这里不进行讨论。

    AreaRegistration文件

    一个AreaRegistration文件是这样的: AdminAreaRegistration.cs 请注意命名规范,MVC这样的约定氛围很浓重的框架,最好按照规定命名。

    using System.Web.Mvc;
    
    namespace WebSite.Areas.Admin
    {
        public class AdminAreaRegistration : AreaRegistration
        {
            public override string AreaName
            {
                get { return "Admin"; }
            }
    
            public override void RegisterArea(AreaRegistrationContext context)
            {
                context.MapRoute(
                    "Admin_default",
                    "Admin/{controller}/{action}/{id}",
                    new {controller = "Home", action = "Index", id = UrlParameter.Optional}
                    );
            }
        }
    }

    当然使得这个Area注册生效的源头是Global.asax 里面的 RegisterAllAreas 方法

        public class MvcApplication : HttpApplication
        {
            protected void Application_Start()
            {
                //MVC
                AreaRegistration.RegisterAllAreas();
                GlobalConfiguration.Configure(WebApiConfig.Register);
                FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
                RouteConfig.RegisterRoutes(RouteTable.Routes);

    RouteConfig.cs(位于App_Start文件夹下面)可以设定默认的领域。

    using System.Web.Mvc;
    using System.Web.Routing;
    
    namespace WebSite
    {
        public class RouteConfig
        {
            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
                routes.MapRoute("Default", "{area}/{controller}/{action}/{id}",
                    new {area = "Admin", controller = "Home", action = "Index", id = UrlParameter.Optional},
                    new[] {"WebSite.Areas.Admin.*"}
                    ).DataTokens.Add("area", "Admin");
            }
        }
    }

    Filter

    Filter也不是MVC的标配,但是往往一个复杂的项目会有一些Filter。Filter可以完成很多不同的工作,对于某个环节的输入和输出进行一些干预。当然Filter也必须注册才能使用。FilterConfig.cs

    using System.Web.Mvc;
    
    namespace WebSite
    {
        public class FilterConfig
        {
            public static void RegisterGlobalFilters(GlobalFilterCollection filters)
            {
                //默认错误处理
                filters.Add(new HandleErrorAttribute());
                //日志
                filters.Add(new LoggerAttribute());
                //异常记录
                filters.Add(new ExceptionHandlerAttribute());
                //压缩
                filters.Add(new CompressAttribute());
            }
        }
    }

    压缩

    using System.IO.Compression;
    using System.Web.Mvc;
    
    namespace WebSite
    {
        OnActionExecuting的时候,可以设定输出的压缩
        public class CompressAttribute : ActionFilterAttribute
        {
            public override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                var acceptEncoding = filterContext.HttpContext.Request.Headers["Accept-Encoding"];
                if (!string.IsNullOrEmpty(acceptEncoding))
                {
                    acceptEncoding = acceptEncoding.ToLower();
                    var response = filterContext.HttpContext.Response;
                    if (acceptEncoding.Contains("gzip"))
                    {
                        response.AppendHeader("Content-encoding", "gzip");
                        response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
                    }
                    else if (acceptEncoding.Contains("deflate"))
                    {
                        response.AppendHeader("Content-encoding", "deflate");
                        response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
                    }
                }
            }
        }
    }

    错误处理

    OnException 出现错误的时候可以进行一些处理

    using System.Web.Mvc;
    using InfraStructure.Log;
    using InfraStructure.Utility;
    
    namespace WebSite
    {
        public class ExceptionHandlerAttribute : HandleErrorAttribute
        {
            public override void OnException(ExceptionContext actionExecutedContext)
            {
                var actionName = actionExecutedContext.RouteData.Values["action"].ToString();
                var controllerName = actionExecutedContext.RouteData.Values["controller"].ToString();
                var username = string.Empty;
                if (actionExecutedContext.HttpContext.Session[ConstHelper.Username] != null)
                {
                    username = actionExecutedContext.HttpContext.Session[ConstHelper.Username].ToString();
                }
                ExceptionLog.Log(username, actionName, controllerName, actionExecutedContext.Exception.StackTrace);
            }
        }
    }

    日志

    如果希望每个Action都有执行日志可以这样,OnActionExecuted之后,可以添加一些动作

    using System.Web.Mvc;
    using InfraStructure.Log;
    using InfraStructure.Utility;
    
    namespace WebSite
    {
        public class LoggerAttribute : ActionFilterAttribute
        {
            public override void OnActionExecuted(ActionExecutedContext filterContext)
            {
                var actionName = filterContext.ActionDescriptor.ActionName;
                var controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
                var username = string.Empty;
                if (filterContext.HttpContext.Session[ConstHelper.Username] != null)
                {
                    username = filterContext.HttpContext.Session[ConstHelper.Username].ToString();
                }
                InfoLog.Log(username, actionName, controllerName);
            }
        }
    }

    安全

    如果每个Controller都进行相同的安全检查,代码量很庞大,可以设定一个SecurityController,然后所有的Controller都继承与SecurityController。

    using InfraStructure.Helper;
    using InfraStructure.Log;
    using InfraStructure.Table;
    using InfraStructure.Utility;
    
    namespace WebSite.Areas.Admin.Controllers
    {
        public class DataViewSetController : SecurityController
        {
    
            // GET: Develop/DataViewSet
            public ActionResult Index()
            {
    
                var list = OwnerTableOperator.GetRecListByOwnerId<DataViewSet>(DataViewSet.CollectionName, OwnerId);
                //MasterTable Sort Function
                //list.Sort((x, y) => { return x.Rank - y.Rank; });
                ViewData.Model = list;
                return View();
            }

    本质上还是在运行Action的时候(OnActionExecuting),进行一些抢先过滤。

    using System.Web.Mvc;
    using BussinessLogic.Security;
    using InfraStructure.Utility;
    
    namespace WebSite
    {
        public class SecurityController : Controller
        {
            /// <summary>
            ///     验证
            /// </summary>
            /// <param name="filterContext"></param>
            protected override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                if (Session[ConstHelper.OwnerId] == null)
                {
                    filterContext.Result = RedirectToAction("Index", "Home", new { area = "Admin" });
                    return;
                }
                OwnerId = Session[ConstHelper.OwnerId].ToString();
                EmployeeInfoType = Session[ConstHelper.EmployeeInfoType].ToString();
                Username = Session[ConstHelper.Username].ToString();
                AccountCode = Session[ConstHelper.Account].ToString();
                Privilege = Session[ConstHelper.Privilege].ToString().GetEnum(PrivilegeType.None);
                ViewBag.Privilege = Privilege;
                ViewBag.OwnerId = OwnerId;
            }
        }
    }

    MVC6

    Area

    如果你上网检索关于Area的信息,下面的文章大概会引起你的关注,可惜里面的Sample已经没有了。
    using areas in asp-net-5

    如果你想完整的看一个MVC6带有Area的例子,MusicStore则应该可以满足你的需求。
    MusicStore示例

    Area的目录结构还是和MVC5一样:MusicStore/Areas/Admin/
    这个也没有什么好修改的。至于Area的路由问题,将在路由里面进一步讨论。

    Filter

    下面这篇文章很好的介绍了Filter的问题,目录结构还是和MVC5一样(原作者已经更新到RC2了)

    asp-net-5-action-filters

    Because the filters will be used as a ServiceType, the different custom filters need to be registered with the framework IoC. If the action filters were used directly, this would not be required.

    这里也是需要为Filter进行注册了,只是注册的方式变成下面的方式:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
    
        services.AddScoped<ConsoleLogActionOneFilter>();
        services.AddScoped<ConsoleLogActionTwoFilter>();
        services.AddScoped<ClassConsoleLogActionOneFilter>();
    }

    工具制作(计划中)

    界面和整体流程

    我在考虑是否要做这样一个工具:
    工具的界面如下所示,两个文本框,一个是MVC5目录,一个是MVC6目录。一个升级按钮。
    然后一键可以将MVC5 尽可能 得升级到MVC6。

    整体工具的框架也很简单

            /// <summary>
            ///     Start To Upgrade MVC5 to MVC6
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnUpgrade_Click(object sender, EventArgs e)
            {
                //测试用开始
                txtMVC5Root.Text = @"E:WorkSpaceDominoHRWebSite";
                txtMVC6Root.Text = @"E:WorkSpaceMVCMigratiorLib";
                //测试用结束
    
                SystemManager.mvc5Root = txtMVC5Root.Text;
                SystemManager.mvc6Root = txtMVC6Root.Text;
                //Init(Log准备)
                SystemManager.Init();
                //Analyze The Folder
                StructureAnalyze.Analyze();
                //Upgrade
                MainUpgrade.Upgrade();
                //Terminte(Log关闭)
                SystemManager.Terminate();
            }

    这里的代码省略LOG输出等次要但是必须的功能介绍,一个好的工具必须有LOG。同时,这个工具不能对原来的MVC5文件进行任何的修改,这个是大原则,所有的文件都必须复制到新的目录下面进行修改

    在考虑MVC6的目录之前,我们先来看看如何分析MVC5的目录结构。
    这里很简单,就是把顶层目录都遍历一遍即可,没有什么技术含量。当然,由于目录信息都保存起来了,很容易做出HasArea,HasFilter这样的属性方法。

            /// <summary>
            /// Has Areas
            /// </summary>
            public static bool HasAreas {
                get {
                    return RootFolder.ContainsKey(strAreas);
                }
            }
    
            /// <summary>
            /// Analyze 
            /// </summary>
            public static void Analyze() {
                //Get Top Level Folder List
                foreach (var topLevelFolder in Directory.GetDirectories(SystemManager.mvc5Root))
                {
                    string folderName = new FileInfo(topLevelFolder).Name;
                    RootFolder.Add(folderName, topLevelFolder);
                    SystemManager.Log("topLevelFolder:" + folderName);
                }
                AppendReport();
            }

    本文已经同步到 http://www.codesnippet.info/Article/Index?ArticleId=00000024
    ASP.NET从MVC5升级到MVC6 总目录

  • 相关阅读:
    Objective-C 排序
    Objective-C 工厂方法
    Objective-C 关键字:retain, assgin, copy, readonly,atomic,nonatomic
    iOS UINavigationController的使用
    iOS UITabBarController的使用
    iOS UISearchController的使用
    iOS中延时执行的几种方式的比较和汇总
    iOS适配 旧项目工程在iOS9下不能正常显示
    iOS Block界面反向传值
    iOS Block简介
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/5509751.html
Copyright © 2020-2023  润新知