Design of controller for CRUD full-stack programming architecture

Source: Internet
Author: User
Tags tojson

Page

This interface I use jquery miniui to do, when you fully understand the entire design can easily switch to other JS framework, personally think like Muniui,easyui and so on, such as the Web interface can be done and WinForm similar framework, especially for the background management system. To discuss the design of the controller must be combined with the interface, here I give the interface and controller code, this is mainly about the controller code, the next one to talk about the design of the interface.

Forget to say, Iveiwmodel is a dto or ViewMode interface, my application is generally not strictly distinguish between ViewMode and DTO, this interface after a long ID property,

The code is as follows:

Using system;using system.collections.generic;using system.componentmodel.dataannotations;using System.Linq;using System.reflection;using system.web.mvc;using system.web.routing;using coralcode.framework.extensions;using Coralcode.framework.log;using coralcode.framework.models;using coralcode.framework.mvc.extensions;using Coralcode.framework.mvc.models.miniui;using coralcode.framework.mvc.template;using Coralcode.Framework.Services; Using coralcode.framework.validator;using newtonsoft.json;using ViewType = Coralcode.framework.mvc.models.miniui.viewtype;namespace coralcode.framework.mvc.controlcontent{Public Abstract  Class Crudcoralcontroller<tmodel, Tsearch, torder>: Contextcoralcontroller where Tmodel:class, IViewModel, New () where tsearch:searchbase, new () where torder:orderbase, new () {private ReadOnly ICRUDC        Oralservice<tmodel, Tsearch, torder> _service; Protected Crudcoralcontroller (Icrudcoralservice<tmodel, Tsearch,Torder> service) {_service = service; } protected override void Initialize (RequestContext requestcontext) {base.            Initialize (RequestContext);            var routevalues = Request.getroutevalues (); The configuration of the page Viewbag.title = GetType ().            GetDescription ();            Viewbag.editurl = Url.action ("AddEdit", routevalues);            Viewbag.deleteurl = Url.action ("Batchdelete", routevalues);            Viewbag.listurl = Url.action ("List", routevalues);            Viewbag.pageurl = Url.action ("Pagesearch", Request.getroutevalues ());        Viewbag.showpager = true;            } [HttpGet] public virtual ActionResult Index () {var viewmodeltype = typeof (TModel); var properties = viewmodeltype.getproperties (Bindingflags.ignorecase | BindingFlags.Public |            BindingFlags.Instance);            var columns = new list<datagridcolumn> (); foreach (Var propertyiNFO in properties) {var descattr = propertyinfo.getcustomattribute<gridcolumnattribute> ()                ;                if (descattr = = null) continue;                var column = Descattr.datagridcolumn; if ((column).                ViewType & viewtype.list) = = 0) {continue; } if (string. Isnullorwhitespace (column. Field)) {column.                Field = Propertyinfo.name; } columns.                ADD (column);                var datetype = propertyinfo.getcustomattribute<datatypeattribute> ();                if (Datetype = = null) continue;                    Switch (datetype.datatype) {case DataType.Custom:break; Case DataType.DateTime:column.                        Renderer = "Ondatetimerenderer";                    Break       Case Datatype.date:                 Column.                        Renderer = "Ondaterenderer";                    Break Case DataType.Time:column.                        Renderer = "Ontimerenderer";                    Break                    Case DataType.Duration:break;                    Case DataType.PhoneNumber:break;                    Case DataType.Currency:break;                    Case DataType.Text:break;                    Case DataType.Html:break;                    Case DataType.MultilineText:break;                    Case DataType.EmailAddress:break;                    Case DataType.Password:break;                    Case DataType.Url:break;                    Case DataType.ImageUrl:break;                Case Datatype.creditcard:        Break                    Case DataType.PostalCode:break;                    Case DataType.Upload:break;                Default:throw new ArgumentOutOfRangeException ();            }} viewbag.header = columns;            Listbinddata ();        Return View (New Tsearch ()); } [HttpPost] public virtual Jsonresult List (Tsearch search) {return ToJson (_service.        Search);            } [HttpPost] public virtual Jsonresult pagesearch (Tsearch search,pageinfo page,torder order) { Return ToJson (_service.        Pagesearch (Page,search, order)); }///<summary>///here for editing//</summary>//<param name= "id" &GT;&LT;/PARAM&G        T            <returns></returns> [HttpGet] public virtual ActionResult AddEdit (long id) { TModel model = ID.HasValue? _service. Get (ID.            Value): New TModel ();            Addeditbinddata (model);        return View (model);            } [ValidateInput (false)] [HttpPost] public virtual Jsonresult AddEdit (TModel model) { try {if (!                Modelstate.isvalid) return Ajaxerrorresult (Modelstate.geterroremessage ());                var ajaxmessage = validateandpreproccess (model); if (ajaxmessage.state! = resultstate.success) {return Ajaxerrorresult (Ajaxmessage.messa                GE); } if (model. Id < 1) _service.                Create (model); Else _service.            Modify (model); } catch (Exception ex) {LoggerFactory.Instance.Error ("{0} edit generated error; Data: {1}", ex, typeof (                TModel), Jsonconvert.serializeobject (model?? New TModel ())); Return Ajaxexceptionresult (ex);        } return Ajaxokresult (); }//<summary>//Business verification///For example user name unique///</summary>//<param name= "mod El "></param>///<returns></returns> protected virtual Resultmessage Validateandpreproc Cess (TModel model) {if (!                    EntityValidatorProvider.Validator.IsValid (model)) return new Resultmessage { state = Resultstate.fail, Message = string.            Join ("; <br/>", EntityValidatorProvider.Validator.GetInvalidMessages (model))};        return new Resultmessage {state = resultstate.success}; } protected virtual void Listbinddata () {}///<summary>///here to extend bound data/        </summary> protected virtual void Addeditbinddata (TModel model) {//The operation used to do data binding here      }  [HttpPost] public virtual Jsonresult Delete (long id) {return this. Batchdelete (ID.        ToString ()); } [HttpPost] public virtual Jsonresult batchdelete (string IDs) {if (string.            Isnullorwhitespace (IDS)) return Ajaxerrorresult ("parameter cannot be null"); try {var idlist = IDs. Split (', '). ToList ().                ConvertAll (Convert.toint64);                if (Idlist.count < 1) return Ajaxerrorresult ("parameter cannot be null"); _service.            Remove (idlist); } catch (Exception ex) {LoggerFactory.Instance.Error ("{0} edit generated error; Data: {1}", ex, typeof (                TModel), Jsonconvert.serializeobject (IDs));            Return Ajaxexceptionresult (ex);        } return Ajaxokresult (); }} public abstract class Crudcoralcontroller<tmodel, tsearch>: Crudcoralcontroller<tmodel, Tsearch, Order base> where Tmodel:class, Iviewmodel, New () where Tsearch:seArchbase, new () {protected Crudcoralcontroller (Icrudcoralservice<tmodel, Tsearch, orderbase> service): b ASE (service) {}} public abstract class Crudcoralcontroller<tmodel>: Crudcoralcontroller<tm Odel, Searchbase, orderbase> where Tmodel:class, Iviewmodel, new () {protected Crudcoralcontroller (I Crudcoralservice<tmodel, Searchbase, orderbase> Service): Base (Service) {}}}

Operation

The page configuration is primarily configured in the Controler.initialize method. Here's a place to note that you must bring routedata where you generate the URL, which can take full advantage of MVC's valueprovider design, and the menu URL can provide a value binding for the binding of the query and the model. This section will be explained in detail after the full demo is released.

Add/Edit

Here I have added and edited as one to treat, most of the case, when the ID of 0 is considered to be new, when the ID is not 0 is the editor. Of course if you want to separate just add a configuration and a method and combine the interface JS,
The extension must be allowed

Delete

Here I only use the method of bulk deletion, the interface should be given is a checkbox, select and then click Delete. Here notice that the interface transmits the data is "," separate string, after parsing do delete operation.

Inquire

The query provides two types of non-paged and paginated pages. Paging words with Showpager to configure. Most of the background list needs paging, but if combined with a level three menu, combined with the URL routedata, you can divide the data into a certain amount of data without paging with the list is also convenient. I have no sort of function on the interface here, I will sort it out later when I organize the demo.

List data binding

In the index method we first take out the metadata of the model, the columns need to be bound to the interface, what the data type is, and some of the elements can be defined. For example height, width, of course, preferably with the interface of adaptive use. In addition to the Listbindata this method is not implemented, mainly for the query when binding data. For example, if you have type Combox in your query entity, you can get the type to use with ViewBag to the interface. You can also give the interface some default values, such as you query the entity has a start time, the end time, you can also give a configuration here. Of course, if you query the entity just to provide only one table query, then it is best to write in the constructor.

Page out

Paging and querying only one pageinfo (contains only the current page and number of rows)
PS:MVC binding mechanism can result in the inability to assign a value, or copy the problem of confusion
The property name of the >* PageInfo does not conflict with the property name of the queried entity, unless it is a business need.
>* also be sure not to query entities that define similar Page,search,order attribute names.
>*, such as Area,controller,action, as an entry or a parameter of the attribute also do not have

Adding and editing distinctions and bindings

Edit by ID Whether there is a value to distinguish, if there is a value, then will use the service query to the data binding to the interface, no words will be new out. The Addeditbinddata method is to provide a data source for page bindings, such as the editing interface with Combox, which can be more easily bound. Some people will say can use interface Ajax no flush binding, I suggest is try not to do so, if the interface has dozens of combox here is easy to lead to a large number of Ajax requests, I call it an Ajax disaster , so I would strongly recommend that users use the background to provide data binding, Avoid the above problems.

Validation and preprocessing

The first thing to do after submitting the data is that the MVC comes with the validation, here do a small package, can take out all errors back to the interface, but the best way is that interface MVC client JS do binding work. You can see how the ARTECHMVC explained in detail. In addition here a custom validation is done. Here is the method called validateandpreproccess, because sometimes we need to transfer over the data to do a part of preprocessing, such as IDs this is likely that your service needs a list, this time you can do a conversion. In addition, the validation and preprocessing logic is difficult to distinguish between what is done first, so here are two methods to merge. Pre-processing calls the custom validation, here with the Nlayerapp authentication method, specifically please search, in fact, there is no egg. MVC validation is better than this, but the subsequent import and export will be used for the time being put here, combined with import and export this part.

  public static class Mvcextensions    {public        static string Geterroremessage (this modelstatedictionary state)        {           return string. Join (environment.newline,state. SelectMany (item = Item). value.errors)                . Select (item = Item. errormessage)                . Where (item =!string. Isnullorwhitespace (item)));        }    }

Other Ajaxxxxresult

Divided into success, failure and partial success, partial success will be used when importing data. In the top-level base class of the extension controller it is necessary to provide more methods, even if you do not have anything, it is recommended that you take a position first.

Using system;using system.web.mvc;using coralcode.framework.models;using Coralcode.Framework.Mvc.ActionResults; Namespace coralcode.framework.mvc.controlcontent{public class Coralcontroller:controller {protected Jsonr            Esult Ajaxokresult (Object data = NULL, String message = "Success") {var result = new Resultmessage            {state = resultstate.success, message = message, data = data,            };        return ToJson (result, jsonrequestbehavior.allowget); } protected Jsonresult Ajaxexceptionresult (Exception ex, object data = null) {var result = new R esultmessage {state = resultstate.fail, Message = ex.            ToString (), data = data,};        return ToJson (result, jsonrequestbehavior.allowget);    } protected Jsonresult Ajaxerrorresult (Object data = NULL, String message = "Fail") {        var result = new Resultmessage {state = Resultstate.fail, Message = Mess            Age, data = data,};        return ToJson (result, jsonrequestbehavior.allowget);            } protected Jsonresult Ajaxpartsuccessresult (Object data = NULL, String message = "Partsuccess") { var result = new Resultmessage {state = resultstate.partsuccess, Message = mes            Sage, data = data,};        return ToJson (result, jsonrequestbehavior.allowget);            } protected Jsonresult ToJson (object obj, jsonrequestbehavior behavior = jsonrequestbehavior.allowget) { return new Customjsonresult () {Data = obj, Jsonrequestbehavior = Behavio                    R}; }    }}

Resultmessage

Here generics, mainly used on the server to invoke the API when the data conversion type more convenient, all my Ajax requests have done similar encapsulation, this will be in conjunction with the MVC point of emphasis.

Namespace coralcode.framework.models{public class Basemessage {public Basemessage () {} public BaseM            Essage (resultstate state,string message= "") {state = state;        message = message;        Public Resultstate State {get; set;}    public string Message {get; set;} } public class Resultmessage:basemessage {public Resultmessage () {} public resultmessage (Resultsta        Te state, String message = "", Object Data=null): Base (State, message) {data = data;    Public object Data {get; set;} public class Resultmessage<t>: basemessage {public resultmessage () {} public T Data {get; Set         Public Resultmessage (resultstate state, String message = "", t Data=default (t)): Base (state, message)        {data = data; }} public enum Resultstate {Success, Fail, Partsuccess,    }} 

Customjsonresult

The Jsonresult has been extended, performance is faster, and the problem of long data return to the last two bits of the interface data is lost.

Using system;using system.web;using system.web.mvc;using newtonsoft.json;using newtonsoft.json.linq;namespace coralcode.framework.mvc.actionresults{public class Customjsonresult:jsonresult {public override void Exec Uteresult (ControllerContext context) {if (context = = null) {throw new Argume            Ntnullexception ("context"); } if (Jsonrequestbehavior = = Jsonrequestbehavior.denyget && string.equals (context. HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) {throw new Invalido            Perationexception (); } httpresponsebase response = context.            Httpcontext.response; if (! String.IsNullOrEmpty (ContentType)) {response.            ContentType = ContentType; } else {response.            ContentType = "Application/json"; } if (contentencoding! = null) {Response.            ContentEncoding = contentencoding; } if (Data! = null) {response.            Write (Jsonconvert.serializeobject (Data, New Idtostringconverter ()));  }}} public class Idtostringconverter:jsonconverter {public override object Readjson (Jsonreader Reader, Type objectType, Object Existingvalue, Jsonserializer serializer) {Jtoken JT = Jvalue.readfrom            (reader); Return JT.        Value<long> ();        } public override bool Canconvert (Type objectType) {return typeof (Int64) = = ObjectType; } public override void Writejson (Jsonwriter writer, object value, Jsonserializer serializer) {SE Rializer. Serialize (writer, value.)        ToString ()); }    }}

Ps:
This JS accuracy problem is due to JS itself design time a bug. It's been a long time since we first encountered it, and has been replaced with a string attribute in the class. But then the heart, or from the bottom of the MVC to solve the problem. If there's a problem, don't go around, just do it-_-!

Here attention Jsonrequestbehavior.allowget, interview question Weapon-_-!

PS: Note All of my PS, are stepping on the pit, and is not easy to find the pit.

  

Design of controller for CRUD full-stack programming architecture

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.