Jan 29 2017

Custom Model Binding in Asp.net Core Mvc, 1

Category: Asp.net core | Asp.net | MVCFrancesco @ 06:48


Custom Model Binding in Asp.net Core, 2: Getting Time + Client Time Zone Offset

Custom Model Binding in Asp.net Core, 3: Model Binding Interfaces

This is the first of a series of 3 posts on how to write custom model binders in Asp.net core Mvc. Three posts on three different ways to customize model binding in three different scenarios.

The concept of “simple type” plays a key role in model binding. A Simple type is not just a string, numbers, dates, or any other.net basic type but any type we decide to render as a string in a single input field. Below three examples of types that’s worth to render as “simple types”:

  1. An YouTube Url type, that contains the id of the you tube Url, but is rendered as an actual Url according to some format settings (it might implement IFormattable, for instance), and that “Model Binds” any correct YouTube Url.
  2. A Month type that contains month and year information and that is rendered in Month ISO format (YYYY-MM) into an HTML5 Month input.
  3. A Week type that contains week and year information and that is rendered in Week ISO format (YYYY-Www)  into an HTML5 Week input.

However, we may represent as “simple types” arbitrarily complex data structures by converting them from/to single strings in JSON format. Thus, they are “simple” just because they fit an a single input field.

Types that are not simple are “complex”. In turns, complex types may be split into 2 categories: fixed representation types, and variable representation types. Fixed representation types are rendered with a constant number of input fields whose names do not depend on the value of each instance. Roughly, they are always rendered with the “same input fields”.

For instance, we may represent the Month type mentioned above also as a fixed representation complex type using an input field for the year and another input field for the month.

IEnumerables and generic types must be considered variable representation types if their properties are rendered in different input fields. However, they may always be worked as simple types by using a single input field and JSON serialization.

Simple types, fixed representation types and variable representation types need different model binding techniques.

Variable representation types are the more difficult to deal with and will be analyzed in the last post of the series, since, in general, they require the model binder be invoked recursively to bind their sub-parts.

Simple types are the easier to model bind since it is enough to specify how they must be serialized and de-serialized. The remainder of this post is dedicated to them. We use the Month type example.

As a first step let create a new asp.net core project named “SimpleModelBinding” and let select “no authentication”.

Then create a new Folder called “Types”, and add a new Month structure:

public struct Month
{
    public uint YearNumber { get; private set; }
    public uint MonthNumber { get; private set; }
   

    public Month(uint yearNumber, uint monthNumber)
    {
        YearNumber = yearNumber;
        MonthNumber = monthNumber;
        if (MonthNumber < 1 || MonthNumber > 12) throw new FormatException();
        if (yearNumber < 1) throw new FormatException();
    }
    public static Month MinValue { get { return new Month(1, 1); } }
    public static Month MaxValue { get { return new Month(9999, 12); } }
}
Add conversion to/from DateTime:
public DateTime ToDateTime()
{
    return new DateTime((int)YearNumber, (int)MonthNumber, 1);
}

public static Month FromDateTime(DateTime t)
{
    return new Month((uint)t.Year, (uint)t.Month);
}

public static implicit operator Month(DateTime t)
{
    return FromDateTime(t);
}

public static implicit operator DateTime(Month m)
{
    return m.ToDateTime();
}

Finally add also ToString and Parse methods:

public override string ToString()
{
    return string.Format("{0:0000}-{1:00}", YearNumber, MonthNumber);
}

public static Month Parse(string s)
{
    return FromDateTime(DateTime.Parse(s));
}

public static bool TryParse(string s, out Month m)
{
    DateTime dt;
    var res = DateTime.TryParse(s, out dt);
    if (res) m = FromDateTime(dt);
    else m = new Month(1, 1);
    return res;
}

Add month and year may be useful too:

public Month AddMonths(int months)
{
    if (months == 0) return this;
    months = (int)MonthNumber + months;
    var years = months / 12;
    months = months % 12;
    if (months < 0)
    {
        months += 12;
        years--;
    }
    return new Month((uint)(years + YearNumber), (uint)(months));

}
public Month AddYears(int years)
{
    return new Month((uint)(YearNumber + years),
        MonthNumber);
}

If you want you may also define all comparison operators.

Since we already have adequate parsing and ToString methods we are very close to our goal.

We need just to inform Asp-net core Mvc model binding engine on which functions to call to serialize/de-serialize the Month type. This, doesn’t require the definition of a custom model binder but the definition of a TypeConverter that is able to convert between Month and string. In fact, Asp-net core Mvc model binding engine assumes that a type is “simple” exactly when a similar TypeConverter exists.

Let add a new class called MonthTypeConverter to our Types folder:

using System;
using System.ComponentModel;
using System.Globalization;

namespace SimpleModelBinding.Types
{
    public class MonthTypeConverter : TypeConverter
    {
        public override bool CanConvertFrom(
            ITypeDescriptorContext context,
            Type sourceType)
        {
            return sourceType == typeof(string) ||
                sourceType == typeof(DateTime);
        }
        public override object ConvertFrom(ITypeDescriptorContext context,
            CultureInfo culture, object value)
        {
            return value is string ? Month.Parse(value as string) :
                Month.FromDateTime((DateTime)value);
        }
        public override bool CanConvertTo(ITypeDescriptorContext context,
            Type destinationType)
        {
            return destinationType == typeof(string) ||
                destinationType == typeof(DateTime);
        }
        public override object ConvertTo(ITypeDescriptorContext context,
            CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType == typeof(string))
                return ((Month)value).ToString();
            return ((Month)value).ToDateTime();
        }
    }
}

The code is self explicative two bool functions that return true if the conversion from/to a type is possible and two functions that actually perform the conversion from/to. I enabled conversion from/to both DateTime and string but for the purpose of model binding conversion from strings is enough.

Now let declare that this type converter is associated with the Month struct by decorating the Month definition as shown below:

[System.ComponentModel
    .TypeConverter(typeof(MonthTypeConverter))]
public struct Month
{
    ...
    ...

Done! Now we need just to test our Month struct.

Go to the HomeController and substitute the Index method with:

 

public IActionResult Index(Nullable<Month> monthTest)
{
    return View(monthTest);
}

Then go to “Views\Home\Index.cshtm” and replace the whole content with:

@model Nullable<SimpleModelBinding.Types.Month>
@{
    ViewData["Title"] = "Simple Type Model Binding Test";
    var monthTest = Model;
}

<h2>@ViewData["Title"]</h2>

<form asp-action="Index" asp-controller="Home" >
    <div class="form-group">
        <label asp-for="@monthTest">Month:</label>
        <input asp-for="@monthTest" type="month" class="form-control">
    </div>
    <button type="submit" class="btn btn-default">Submit</button>
</form>

Model must be assigned to the variable monthTest otherwise the input field would have empty name and id.

This problem arises because in our very simple test the month struct is not a property of a bigger model. With our trick the input field is named “monthTest” that must match the name of the parameter of the Home controller Index method.

Now select a browser that supports input of type Month (last versions of Edge, Safari, Chrome, Firefox, will do) and run the project.

Select a month, and before submitting place a breakpoint in the Index action method. Once the breakpoint is hit you should see that the month parameter contains the month you have chosen in the browser:

SimpleModelBinderDebug

 

 

 

 

 

In a similar way you might define a Week type and a custom model binding for it.  The Asp.net core version of the Mvc Controls Toolkit, contains Week and Month types together with custom model binding, extensions of RangeAttribute and all validation rules, fallbacks for browsers that do not support any HTML5 and more…

 

That’s all for now

In a short time the second post of our series.

Stay tuned!

Francesco

Tags: , , ,

Dec 2 2016

Increasing productivity in your Asp.net core projects

Category: Asp.net | Asp.net core | MVCFrancesco @ 07:47

Often, during web development we complaint about the time we spend in “standard tasks” and dream of coding just our application peculiarities, thus concentrating just on our specific problem. For sure project templates and scaffolding save some “set up time” and avoid errors, but they do not save too much coding time.

In this post I’ll describe some good practices to increase web pages productivity at the price of some more set up time, and  how the new Asp.net core version of the Mvc Controls Toolkit  may help you with this. For the ones new to the Mvc Controls Toolkit, the Mvc Controls Toolkit is an open source project released with the same license of the whole Asp.net core project, so you may freely use it with no limitations and may also participate to its improvement.

The problem with most of “standard tasks” is that they are not “completely standard” so they cannot be completely automated. However, for each of them we may somehow define and automate a kind of “average task” where we can reach 90% of all actual tasks with small manual modifications. We increase further productivity if these manual modifications are achieved with name conventions, and declarations, such as, for instance, data annotations, options objects, and Tag-Helper attributes.

So for instance you might spend some set-up time to define a few “standard submit forms”, an automated procedure to create them given a few declarative information, and then use them to produce quickly, say 90%, of your views. That 90% is not a quite random number, but the result of statistics I carried out with the help of some of my customers. In fact, on the average 80-90% of all Views of a typical business application are quite standard and just 10-20% require a more complex design. In turn, among the last 10-20% just 3-7% are peculiar to the specific project since the remaining 7-13% consist of instances of general problems, so we may consider automating also part of them.

In the remainder of this post I’ll analyze different project areas that might benefit from this approach and that is worth to “attack”, pointing out the kind of automation to adopt and how the Mvc Control toolkit might help you in the task.

Business and DB Layer

The simplest optimization in this area is avoiding manual copies of DB model properties into ViewModel/DTO properties:

.Select(m => new InvoiceViewModelShow
                {
                    Id = m.Id,
                    Amount = m.Amount,
                    Reference = m.Reference,
                    FileName = m.FileName,
                    Date = m.Date,
                    Start = m.Start,
                    Stop = m.Stop,
                    ShipName = m.Ship.Name,
                    Paid = m.Paid,
                    Approved = m.Approved,
                    ....
                    ...,

                }).ToListAsync();

You might say that’s easy, with AutoMapper! Unluckily you can’t use AutoMapper since the above expression doesn’t perform a copy operation between two in-memory objects, but it is translated into an SQl query. Extracting the whole DB objects from the database and then copying them into DTO/ViewModels with AutoMapper would be unefficient, since you might extract a lot information you don’t need from the Data Base. So, the only solution is creating dynamically LinQ queries.

The MvcControlsToolkit.Core.Business Nuget package that is a completely independent part part of the Mvc Controls Toolkit contains a projection operator that do exactly this job. It uses a same name convention and nested objects like Ship.Name are mapped by concatenating all property names: Ship.Name ===> ShipName. User must specify just properties that doesn’t conform to the name convention. Expression content is not limited to a creation operator but may contain also nested conditions with several ViewModel creations in the various condition branches, like in the example below:

m => m.Maintenance == null ?
   new ProductViewModelDetail{}:
   new ProductMaintenanceViewModelDetail{
       MaintenanceYearlyRate = (decimal)m.Maintenance.YearlyRate
   }

Please notice that the ProductViewModelDetail constructor doesn’t contain any property since all properties may be inferred using the name convention.

Expressions are cached in various ways to avoid the performance cost of re-creating them each time they are used.

Please refer to the official documentation for more information.

Further speed-up may be achieved by defining generic CRUD Repositories that takes care of all main single-table operations: paged retrieval with projection on a ViewModel, detail retrieval, and all update operations that receive directly ViewModels/DTOs as parameters.

MvcControlsToolkit.Core.Business contains a DefaultCRUDRepository<Ctx, M> class where Ctx is the DB context type and M the DB model type, that is able to update automatically also entities related to M. It implements the not generic interface ICRUDRepository, so Ctx, and M may be hidden to the presentation layer. In fact all ICRUDRepository operations have the format: Add<T>, Delete<U>, Update<T>, UpdateList<T>. UpdateList<U>, etc. Where all generics are ViewModel/DTO types. Please refer to the documentation for more details, and further useful properties .

You may inherit from DefaultCRUDRepository<Ctx, M> or build your own generic class and then add also further operations that recur in several places, and with several types in your application.

Controllers

You may speed up Controller code implementation in several ways, namely:

  • By creating generics based abstract base controllers to inherit from.
  • By implementing ActionFilters for recurring controller pre/post processing.
  • By implementing MiddleWare that pre-processes all requests
  • By implementing controller utilities classes.

Base controller generics are usually ViewModels/DTOs types. In case of WebApi controllers their main purpose is handling client/server communication protocols. In fact for better modularity and reliability all application WebApi controllers should be based on well defined abstract protocols designed during your application preliminary analysis.

Also standard controllers may benefit of inheriting from base controllers with “standard action methods”, to handle recurrent “standard” Ajax update tasks , such as showing a detail show/edit modal, and updating a modified grid item.

Both type of controllers need a JavaScript library counterpart that interfaces them with the client side. So base controllers adoption factor out and “standardize” both server side and client side code.

Base controllers “standard” action methods may be connected with problem specific business logic either by calling protected virtual methods the inheriting controller may override, or by accepting implementations of "standard" repository interfaces as constructor arguments. Generic Repository interfaces may be instantiated by problem specific implementations passed by the inheriting controllers, which in turn receive them in their constructors through dependency injection.

At moment Mvc Controls toolkit contains just a single standard ServerCrudController<VMD, VMS, D> controller that offers Ajax assistance to Views showing item lists. More specifically, it offers automatic Ajax assistance to pages in-line Ajax item updates, and in showing detail Show/Edit modals. VMD is the item detail ViewModel type , VMS the in-line item ViewModel, and D the principal key type of both of them.

ServerCrudController<VMD, VMS, D> uses the ICRUDRepository interface to communicate with the business layer, but it has also various properties and methods the inheriting controller may override to customize further action methods behavior. For detail please refer to the official documentation.

In future versions we will add also WebApi controllers implementing useful protocols, as well as facilities to get easily filtering and sorting conditions passed in the query string in OData format.

SercerCrudController is a good example of how to use a standard controller, and how to connect it with business logics:

public class CGridsController :
    ServerCrudController<ProductViewModelDetail,
        ProductViewModel, int?>
{
    public CGridsController(ProductRepository repository,
        IStringLocalizerFactory factory, IHttpContextAccessor accessor)
        : base(factory, accessor)
    {
        Repository = repository;
    }
    public async Task<IActionResult> Products(int? page)
    {
        int pg = page.HasValue ? page.Value : 1;
        if (pg < 1) pg = 1;

        var model = new ProductlistViewModel
        {
            Products = await Repository.GetPage<ProductViewModel>(
            null,
            q => q.OrderBy(m => m.Name),
            pg, 5)
        };
        return View(model);
    }      
}

repository of type ProductRepository injected with DI in the inheriting controller constructor is assigned to the Repository base controller property of type ICRUDRepository. This is enough to connect ServerCrudController  ajax-assistance action methods to the application business logic. Then, we add the Action Method that prepares data for the View that is enhanced with Ajax assistance.

For sure base generic controllers are the most powerful tool to factor out controller code, but request pre/post processing with either MiddleWare  or per-controller ActionFilters may ensure further improvements and contribute to a cleaner modular design. If you have doubts about how to implement your pre/post processing consider that with the new Asp.net core 1.1 MiddlewareFilter you may use any MiddleWare also as an Action filter. Examples of how useful request pre/post processing code is factored-out by Middleware are: authentication cookies processing, culture selection processing, and in general user preferences processing discussed in the last section of this post. In the next version of the Mvc Controls Toolkit we will add Middleware for processing also filtering/sorting information contained in the query string in OData format.

Views

Usage of standard templates that render data according to ViewModel data annotations and/or parameters drastically reduces the development time, and contribute to Web Pages standardization. In turn, Web pages standardization reduce the time needed for a user to learn how to use the web application.  One may increase, the “scope” of a template by allowing the developer to customize part, of it, as for instance, how a single property is rendered.

Mvc Controls Toolkit templates rendering is organized around RowTypes and Columns. RowTypes contain overall infos and templates for rendering a whole data item while Columns contain infos and templates for rendering a single property. RowTypes templates call Column templates, so the developer may provide “standard” RowTypes and Column templates, and then on each page he/she may control how to display data items by providing adequate settings for RowType/Columns, and by providing some custom Column template. RowTypes, and Colum settings are automatically extracted from data annotations and property types but user my override them by providing supplementary infos in RowType/Column description TagHelpers.

Here an example of an edit form rendered with a standard bootstrap-based layout and whose settings are entirely extracted from data annotations and property types.Order, input are displayed is based on the Order property of the DisplayAttribute, while the number of Bootstrap grid system slots assigned to each input is based on percentage width specifications contained in ColumnLayoutAttributes. Developer may provide specifications for several screen widths. The kind of input is selected automatically by the standard Column template based on the property type/DataTypeAttribute. So, for instance,  enums are rendered with a selects and boolean with a checkboxes.The above detail-form TagHelper uses global templates defined with partial views inside the Mvc Controls Toolkit dlls. However, in general, user may specify the name of a different partial view, or the name of a ViewComponent  in the detail-form  tag itself. The developer may also override globally the standard template Partial Views by adding Partial Views with the same names in the Shared folder.

Here an example where rendering has been customized with the help of row-type and column TagHelpers. The exterrnal-key-remote tag specifies that the TypeId property contains an external key, and provides all needed information for the user to select the right key value with an autocomplete, by typing the display names associated to the various keys. Settings specified in the row-type tag are applied only if the ViewModel is the ProductMaintenanceViewModelDetail subclass of the  ProductViewModelDetail base ViewModel, otherwise settings specified directly in the detail-form tag are applied.

Here “standard templates” featuring a grid with edit in-line Ajax capabilities based on the Ajax assistance furnished by the ServerCrudController<VMD, VMS, D>.

User options

Another area where you may achieve further development-time optimizations is User option handling. Having, a centralized register containing all user options with the possibility to inject them where needed via dependency injection may help to factor out some code and simplify  your overall design. Basically you may have  user options sources and stores all attached to an unique global per-request register. Sources may be input fields, url parameters and cookies for unlogged user and User Claims or custom tables for logged users. Cookies, User Claims, and custom tables may work also as stores where to save user options received through input fields or url parameters.

The MvcControlsToolkit.Core.Options nuget package (that is a completely independent part of the Mvc Controls Toolkit) offers all services described above. You may collect user options provided through input forms or url parameters without writing controller code since they are automatically processed by MvcControlsToolkit.Core.Options middleware. Then you may save them in cookies, user claims and/or custom tables with no need to write any code. Developer may configure all above services with a few simple declarative options in the MvcControlsToolkit.Core.Options middleware. It is a typical example of how MiddleWare may speed up controllers development.

For more information please refer to the official documentation.

 

That’s all for now!

More examples and tutorials in posts to come!

Francesco

 

.

 

 

 

Tags: , , ,

Jul 17 2016

Available Asp.net core version of the Mvc Controls Toolkit Live Examples!

New 1.0.1 bugs fix release of the Mvc Controls toolkit! Available also Live Examples at this link!

Enjoy!  & Stay tuned

In a short time ajax update server grid and batch update server grid

Francesco

Tags: , , , ,