MVC extended Design for all-stack programming architecture of CRUD

Source: Internet
Author: User

MVC execution Process

Extension of the route

I understand that the routing function has the following several

    • SEO optimization, with "/" Separate URL crawler more love to eat
    • Separation of physical and logical files, URLs are no longer mapped by file path
    • The choice of controller,action

Extension of the MVC route

To tell the truth about MVC's routing I seldom do extensions, and in the MVC4 era, I rewrite the case of the URL, and after MVC5, MVC comes with the configuration to lowercase the URL. But there's a configuration that has to be mentioned. That is area, and after your system reaches a certain size, it will be easier for controllers to manage it through area. This gives me the area extension, very simple but important, notice that the subclass must end with Arearegistration, and also follow the Convention is limited to the principle of configuration, of course you can rewrite.

Public abstract class Arearegistrationbase:arearegistration   {public       override string AreaName       {           get {               var item = GetType (). Name;               return item. Replace ("Arearegistration", "");           }       }       public override void Registerarea (AreaRegistrationContext context)       {            context. Maplowercaseurlroute (            areaname + "_default",            areaname.tolower () + "/{controller}/{action}/{id}",            New {action = "Index", id = urlparameter.optional}            );            GlobalConfiguration.Configuration.Routes.MapHttpRoute (                areaname + "Api",                "api/" + areaname + "/{controller }/{action}/{id} ",                new {area = AreaName, id = routeparameter.optional, namespacename = new[] {this. GetType (). Namespace}}            );}}   

Extension of the WEBAPI route

The above MVC route also registered the route of the API, of course, there is a better way, because WEBAPI, basically do not need url.action and htmlaction, this route out of the stack of policy, do not need to go through the route to generate the URL, so
We only need to do the parsing of the route, and Webapi does not provide the own area mechanism, so I expanded the defaulthttpcontrollerselector, get to the route area and controller parameters
and then complete the stitching, Then the reflection type lookup, at the beginning of the pre-cache all controllers, so the performance is good, because the original code is anti-compilation obtained, so the LINQ part is a bit bad, and so I back to the company to get the source code and then modify.

Using system;using system.collections.generic;using system.linq;using system.net.http;using System.Text;using System.web.http;using system.web.http.controllers;using System.web.http.dispatcher;namespace coralcode.webapi.route{public class Areahttpcontrollerselector:defaulthttpcontrollerselector {public static Strin    G Coralcontrollersuffix = "Apicontroller";    Private ReadOnly httpconfiguration _configuration;    Private ReadOnly lazy<ilookup<string, type>> _apicontrollertypes;      Private ilookup<string, type> apicontrollertypes {get {return this._apicontrollertypes.value; }} public Areahttpcontrollerselector (httpconfiguration configuration): Base (configuration) {thi      s._configuration = Configuration; This._apicontrollertypes = new lazy<ilookup<string, type>> (New func<ilookup<string, Type>> ( This.    Getapicontrollertypes)); } private Ilookup<string, type> getapicontrollertypes () {return enumerable.tolookup<type, String, type> ((ienumerable<type>) servicesextensions.gethttpcontr Ollertyperesolver (this._configuration. Services). Getcontrollertypes (Servicesextensions.getassembliesresolver (this._configuration. Services), (Func<type, string>) (t = T.name.tolower (). Substring (0, T.name.length-areahttpcontrollerselector.coralcontrollersuffix.length)), (Func<type, Type>) (t =    > t));  } public override Httpcontrollerdescriptor Selectcontroller (Httprequestmessage request) {string controllername = this.      Getcontrollername (Request); if (!string. Isnullorwhitespace (controllername)) {list<type> List = enumerable.tolist<type> (this.        Apicontrollertypes[controllername.tolower ()]);  if (enumerable.any<type> (ienumerable<type>) list) {idictionary<string, object> values = Httprequestmessageextensions.getroutedata (Request).          Values;       String endstring;   if (values.            Count > 1) {StringBuilder StringBuilder = new StringBuilder (); if (values.              ContainsKey ("area")) {stringbuilder.append ('. ');              Stringbuilder.append (values["area"]);              Stringbuilder.append ('. ');            Stringbuilder.append ("controllers"); } if (values.              ContainsKey ("Controller")) {stringbuilder.append ('. ');              Stringbuilder.append (values["Controller"]);            Stringbuilder.append (Areahttpcontrollerselector.coralcontrollersuffix);          } endstring = Stringbuilder.tostring (); } else Endstring = string. Format (". {          0}{1} ", (object) Controllername, (object) areahttpcontrollerselector.coralcontrollersuffix); Type Controllertype = enumerable.firstordefault<type> ((ienumerable<type>) Enumerable.orderby<type, Int> (enumerable.where<type> (ienumerable<type>) List, (Func<type, bool>) (t = T.fullname.endswith (endstring, Stringcomparison.currentcultureignorecase))), (Func<type, int>) (t = enumerable.count<char> ((ienumerable<char>) T.fullname, (Func<char, bool>) (s = = (int) s = =          (46)))); if (controllertype! = (Type) null) return new Httpcontrollerdescriptor (this._configuration, controllername, con        Trollertype); }} return base.    Selectcontroller (Request); }  }}

Controller activation

Controller activation This is the core of the integration of MVC and IOC, with three parts of the IOC

    • Register type of discovery and registration, solve how to find those types that need to be registered and how to register, here I use attribute way to find, with Unity's own registration method to register
    • Resolve types of parsing, how to know a type and instantiate it
    • Lifttime How to control the life cycle of an instance, such as whether to use a singleton, the life cycle also uses Unity's own, mainly used in the single case and each resolution is an instance

MVC needs and IOC activation The first thing we focus on is where to register and where to instantiate, because MVC uses a contract that takes precedence over configuration, all controllers end with "controller", so here I directly load
Assembly, and then find all types to the end of the controller to register just fine, activate the word has the following three ways, the difficulty of the degree of increase in order, nesting depth is also incremented, here I use rewrite
The default defaultcontrollerfactory way to activate, so that you can use their own and other mechanisms to achieve, other ways you can expand themselves.

    • Controllerfactory
    • Icontrolleractivetor
    • Idependencyresolver

Using coralcode.framework.aspect.unity;using coralcode.mvc.resources;using system;using System.Web;using System.web.mvc;using system.web.routing;namespace coralcode.mvc.controllerfactory{public class unitycontrollerfactory:defaultcontrollerfactory {public override IController Createcontroller (RequestContext reques Tcontext, String controllername) {return base.    Createcontroller (RequestContext, controllername);  } protected override IController GetControllerInstance (RequestContext requestcontext, Type controllertype) {if      (Controllertype = = (Type) null) throw new HttpException (404, Messages.mvcbase_notfoundpage); if (! Unityservice.hasregistered (Controllertype)) return base.      GetControllerInstance (RequestContext, Controllertype);    Return (IController) unityservice.resolve (Controllertype); }}}//WEBAPI activates the following using Coralcode.framework.aspect.unity;using system;using system.net.http;using System.web.http.controllers;using System.Web.Http.DiSpatcher;namespace coralcode.webapi.controllerfactory{public class Unitycontrolleractivator: Ihttpcontrolleractivator {public Ihttpcontroller Create (httprequestmessage request, Httpcontrollerdescriptor control Lerdescriptor, Type controllertype) {Ihttpcontroller Httpcontroller = (ihttpcontroller) unityservice.resolve (cont      Rollertype);      Httprequestmessageextensions.registerfordispose (Request, Httpcontroller as IDisposable);    return httpcontroller; }  }}

Filter Execution Logfilter

Here is basically the source code of MVC, just added a log function, grilled MVC source code Everyone must try

Using coralcode.framework.log;using system;using system.web;using system.web.mvc;namespace Coralcode.Mvc.Filters{[ AttributeUsage (AttributeTargets.Class | AttributeTargets.Method)] public class Logexceptionattribute:handleerrorattribute {public override void Onexceptio N (exceptioncontext filtercontext) {if (Filtercontext = = null) throw new ArgumentNullException ("Filterconte      XT ");      Exception Exception = filtercontext.exception; LoggerFactory.Instance.Error (Exception.      ToString ()); if (filtercontext.ischildaction | | filtercontext.exceptionhandled | | (!filtercontext.httpcontext.iscustomerrorenabled | | new HttpException ((string) null, exception). Gethttpcode ()! = 500) | | !this.      Exceptiontype.isinstanceoftype ((object) exception)) return; This.    Handlerviewresultexception (Filtercontext); private void Handlerviewresultexception (Exceptioncontext filtercontext) {String controllername = (string) fi ltercontext.routedata.values["ControlleR "];      String actionname = (string) filtercontext.routedata.values["action";      Handleerrorinfo model = new Handleerrorinfo (filtercontext.exception, Controllername, ActionName);      Exceptioncontext exceptioncontext = Filtercontext;      ViewResult viewResult1 = new ViewResult (); Viewresult1.viewname = this.      View; Viewresult1.mastername = this.      Master;      Viewresult1.viewdata = (viewdatadictionary) new viewdatadictionary

Resultfilter

Here the unified processing of the AJAX request return data to Resultmessage return, if not Jsonresult select Ignore, specifically designed to look at the controller design that section.

Using coralcode.framework.models;using coralcode.mvc.actionresults;using System.web.mvc;namespace coralcode.mvc.filters{public  class Resultmessageattribute:actionfilterattribute  {public    override void Onresultexecuting (ResultExecutingContext filtercontext)    {      Jsonresult jsonresult = (Jsonresult) ( Filtercontext.result as Customjsonresult)?? Filtercontext.result as Jsonresult;      if (Jsonresult = = null)        return;      Jsonresult.data = this. Getresultmessage (jsonresult.data);      Filtercontext.result = (actionresult) jsonresult;    }    Private object Getresultmessage (object data)    {      if (data is Basemessage)        return data;      Return (object) new Resultmessage (resultstate.success, "Success", Data);}}}  

Action execution

To improve the concurrency of the weapon, the best way to use, here is a detailed introduction can be combined with Artec controller synchronization and asynchronous this section, which I personally recommend is the use of return task<actionresult>.

Valueprovider and Modelbinder

The parameters in the URL are used as the data source for the model binding. When you do a level three menu, you can use it, for example, I first add the following data to the data dictionary

var newstype = new Glossary () {Key = "Newstype", Value = "Newstype",           Description = "News", Seq = 0, Title = "News Type", ParentID =-1,};           _glossaryservice.add (Newstype);               _glossaryservice.add (New Glossary () {Key = "recentnews", Value = "Recentnews",            Description = "News Type", Seq = 1, Title = "latest Activity", ParentID = Newstype.id,           });               _glossaryservice.add (New Glossary () {Key = "useractivity", Value = "Useractivity", Description = "News Type", Seq = 2, Title = "Member activity", ParentID = Newstype .           Id,});               _glossaryservice.add (New Glossary () {Key = "Onlinemarket", Value = "Onlinemarket",            Description = "News Type",   Seq = 3, Title = "Online Mall", ParentID = Newstype.id,});               _glossaryservice.add (New Glossary () {Key = "AboutUs", Value = "AboutUs",           Description = "News Type", Seq = 4, Title = "About Us", ParentID = Newstype.id,           }); Repository.UnitOfWork.Commit ();

Then read the data from the field to add the menu

var newsmenu = regist ("News Management", "/portal/home/handerindex?menuid=" + systemmanagermenu.identify + "-newstype",             Systemmanagermenu.identify, systemmanagermenu.identify + "-newstype");         News management         _glossaryservice.getfiltered ("News type"). ForEach (item =         {             regist (item). Title,string. Format ("/portal/news/index?typeid={0}&type={1}", item. Id,item. Title),                 newsmenu.identify, newsmenu.identify + "-" + item. (Id);         });

Load level Three Menu

      <summary>///processing interface///</summary>//      <returns></returns>      Public ActionResult Handerindex (String menuId)      {          Viewbag.tree = string. Empty;          TODO: Request two times, pending          if (menuId = = null)              return View ();          var items = _menuservice.getchildrenmenus (menuId);          Viewbag.tree = jsonconvert.serializeobject (items);          return View ();      

Interface

Then there is a field in search and ViewModel that is typeid so that the value can be automatically bound in List,pagesearch,addoredit.

Public  class Newssearch:searchbase   {public       long? TypeId {get; set;}              public string Title {get; set;}   }

View Discovery and ActionResult execution

MVC default system is weak, when the controller and view more when a file under a lot of content, I have done a modular processing.

Using System.web.mvc;namespace coralcode.mvc.viewengines{public class Themesrazorviewengine:razorviewengine {Publ IC Themesrazorviewengine () {this.        Areaviewlocationformats = new String[3] {"~/themes/{2}/{1}/{0}.cshtml", "~/themes/shared/{0}.cshtml",      "~/themes/{2}/shared/{0}.cshtml"}; This.      Areamasterlocationformats = new String[1] {"~/themes/shared/{0}.cshtml"}; This. Areapartialviewlocationformats = new String[4] {"~/themes/{2}/{1}/{0}.cshtml", "~/themes/{2}/shared/{0      }.cshtml "," ~/themes/shared/{0}.cshtml "," ~/themes/shared/control/{0}.cshtml "}; This.      Viewlocationformats = new String[2] {"~/themes/{1}/{0}.cshtml", "~/themes/shared/{0}.cshtml"}; This.      Masterlocationformats = new String[1] {"~/themes/shared/{0}.cshtml"}; This.        Partialviewlocationformats = new String[2] {"~/themes/{1}/{0}.cshtml","~/themes/shared/{0}.cshtml"}; } public override Viewengineresult Findview (ControllerContext controllercontext, String viewName, String mastername, bo Ol UseCache) {if (ControllerContext.RouteData.Values.ContainsKey ("area") &&!controllercontext.routedata. Datatokens.containskey ("area")) ControllerContext.RouteData.DataTokens.Add ("area"),      controllercontext.routedata.values["area"]); Return base.    Findview (ControllerContext, ViewName, Mastername, UseCache); }  }

Project directory structure such as

The post-release catalog is very clean,

Jsonresult execution and metadata (model metadata delivery mechanism)

This section is described in detail in the Controller design section, please refer to the next step

Summarize
    • Everyone must look at the MVC source code,
    • I want to be able to string the MVC execution process in my head.
    • The main body design has been finished, source code collation, work relatively busy, forgive me,
    • Like please concern, there are questions please leave a message, a headache, sleep, good night

MVC extended Design for all-stack programming architecture of CRUD

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.