ASP.NET MVC

MvcPaging 2.0

 

image

Last week, a new version of the MvcPaging library has been released. This time there are some breaking changes and that’s why the major version number is increased.

What’s new:

  • Simplified API with reduced number of Html.Pager overloads;
  • DisplayTemplate option and PaginationModel;
  • Configurable number of pages.

Simplified API

There have been some requests for extra configuration options, but I didn’t want to add more overloads to the Html.Pager helper. Instead, the number of overloads is reduced drastically:

Html.Pager(int pageSize, int currentPage, int totalItemCount)

and

Html.Pager(int pageSize, int currentPage, int totalItemCount, AjaxOptions ajaxOptions)

We now only have a method with the required parameters and one overload for Ajax scenarios. Also, the Ajax.Pager helper is removed. Note that this is a breaking change, so if you were using the Ajax.Pager helper, you now have to use the Html.Pager with the AjaxOptions overload.

Non-required configuration options are added via the Options() method. This interface also replaces the overloads in the previous version where you could set route values or controller actions. This is the second breaking change. You can now only set these values via the Options method.

Html.Pager(pageSize, pageNumber, totalItemCount).Options(o => o
    .Action("action")
    .AddRouteValue("q", mySearchQuery)
)

Below are all options:

  • Action(string action)

    Sets an alternative action for the pager that is different from the current action.

  • AddRouteValue(string name, object value)

    Adds a single route value parameter that is added to page url’s.

  • RouteValues(object routeValues)

    Adds route value parameters that are added to the page url’s.

  • RouteValues(RouteValueDictionary routeValues)

    Adds route value parameters that are added to the page url’s.

  • DisplayTemplate(string displayTemplate)

    When set, the internal HTML rendering is bypassed and a DisplayTemplate view with the given name is rendered instead. Note that the DisplayTemplate must have a model of type PaginationModel.

  • MaxNrOfPages(int maxNrOfPages)

    Sets the maximum number of pages to show.

DisplayTemplate option

A few people have been asking for configurable rendering, especially since Twitter Bootstrap has become popular. Rajeesh CV submitted a pull request that introduced a view model for the Pager, the PaginationModel. This view model made it very easy to create an option where you can specify a DisplayTemplate that is used for the actual rendering. It works like any other ASP.NET MVC DisplayTemplate and requires a model of PaginationModel. As a bonus, the PaginationModel makes unit testing a lot easier.

The MvcPaging.Demo project has an example DisplayTemplate that renders Html that is compatible with Twitter Bootstrap:

Html.Pager(pageSize, pageNumber, totalItemCount).Options(o => o
    .DisplayTemplate("BootstrapPagination")
    .MaxNrOfPages(14))

image

Configurable number of pages

As you can see in  the screenshot above, the pager can now be configured to show more or less than 10 pages via the MaxNrOfPages() option.

I’d like to thank Rajeesh CV, jbucht01 for the contributions and ideas. For more information, visit the GitHub project page, or install the Pager in your own projects with NuGet.

Actya

Introducing Actya – a .NET CMS that doesn’t get in your way

Actya is a simple open source ASP.NET MVC Content Management System (CMS).

Why on earth would we need another CMS?

Quite often, a CMS is chosen as application framework for custom application development because you’ll get a lot for free: navigation, security and content management (obviously). Custom applications are then developed as modules that run within the context of the CMS. Cuyahoga, the CMS I’ve started  8 years ago works exactly like this.

Rob Conery describes an issue with this solution:

I’ve deployed Big CMS’s before as a solution for clients and every single time we decided to move away. They’re great for getting off the ground – but after a while there’s jus too much friction.

And that’s probably what many of us experience: a CMS gets in the way when your main focus is the custom application. This is the single main reason to create Actya: a CMS that doesn’t get in your way when doing custom development.

CMS as add-on

Actya can act as an add-on library for your application. While developing your custom application in Visual Studio, you can add it with NuGet just like any other library. The first time you run your application after adding Actya, an installer kicks in to ask you where you want to have your CMS data stored, what theme you want to use and which account is the CMS administrator. No further configuration required and nothing has to change in your custom application.

The video below shows this scenario with NuGetGallery as the ‘custom’ application:

Even though Actya is mainly designed to act as an add-on CMS, you can also use it as a simple regular CMS. Download it at from CodePlex downloads page, point an IIS 7+ web site or application to the extracted files, open de site in your browser and the installation starts automatically.

After installation, you can access Actya’s admin pages at http://my-host-or-application/cmsadmin.

RavenDB document database

Here’s the other reason for creating Actya: schema-less NoSQL databases are considered to be ideal for CMS applications because you can put any type of content in it without having to alter a database schema or have some kind of monstrous Entity-Attribute-Value model. I wanted to experience if that claim is true.

Actya uses the .NET NoSQL database RavenDB and it really makes development easier. Not only due to the flexibility of the schema-less design but also to the absence of a mapping layer. Wonderful! A cool feature of RavenDB is the embedded mode where you don’t need a database server at all. Actya uses this mode by default (the data goes in App_Data), but can also connect to an existing RavenDB server.

Requirements

  • ASP.NET 4.0
  • Full-Trust environment

Wanted: Feedback

I’ve released the first alpha version to see if anybody finds this CMS useful. Your feedback will have a have a lot of weight in determining future development. If you have any, please go to http://actya.codeplex.com/discussions and open a discussion with ‘User Feedback’ as topic.

O/R mapping

Entity Framework 4 tips for NHibernate users

The last few weeks, I have worked on a project that uses Entity Framework 4 Code First (let’s call it EF from now). Normally, I use NHibernate for my OR-mapping needs and although EF works almost the same conceptually, there are differences. This post is about some of the issues that an NHibernate user can expect when working with EF.

Many to one associations and introduce a foreign key property

Let’s say it bluntly: EF supports Foreign Key associations  (foreign key id’s in your entities, besides many to one associations)  and you better use them, or you’ll experience a lot of pain. I started to model my entities with ‘proper’ object references but ran into 2 problems:

  • Filtering in collection properties causes select n+1 issues. So forget:
    Order.OrderLines.Where(ol => ol.Product.Id == productId)

    but do:

    Order.OrderLines.Where(ol => ol.ProductId == productId)

    to filter a collection property because the first will load all product instances;

  • When you override Equals() and GetHashCode()in your entities to use only the ID for object equality, you can assign an empty object with only the ID set as reference property in NHibernate but EF doesn’t fall for this trick. This is can be very useful, for example when setting references from a dropdownlist where you only have an ID of the referenced object.

It seems that EF just doesn’t leverage proxies like NHibernate does so it needs to have the actual object instance to do things instead of just the proxy.

The good thing however is that when you’re having both a foreign key ID property and an object reference in EF, these are synced automatically and only one column will be generated in the database and the only real issue is a little pollution of your entity.

Object reference not set to an instance of an object

So you’ve created a nice object graph and saved it in the database. Then after fetching the object graph back, some of the referenced objects are null even when the ID’s of the references are nicely sitting there in the database. WTF???

Well, EF doesn’t automatically load a referenced object unless it’s marked as virtual (lazy) or loaded explicitly via Include(). If you forget both, you’ll end up with the NullReferenceExceptions.

No Dictionary collection mapping

This is something not many people complain about, but I really miss the option to map dictionaries like Map in NHibernate. Also, NHibernate’s List mappings are not supported.

Cascade is a big black box

EF doesn’t have a way to specify how changes in your entity are cascaded into related entities. I’m not sure if this is a good or a bad thing. On one hand I miss having control over this, but on the other hand EF seemed to do well without setting anything.

Out of the box, EF code first generates CASCADE  DELETE database constraints on required associations but when your model gets only a little bit complex, you’ll get errors like “Introducing FOREIGN KEY constraint on table may cause cycles or multiple cascade paths”. Fortunately, you can turn this off in your DbContext:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // Remove cascade delete convention because it causes trouble when generating the DB.
    modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();

    base.OnModelCreating(modelBuilder);
}

Explicitly set state when attaching objects to the DbContext

In NHibernate you can simply update an object that isn’t associated with a Session via Session.Update(). EF can do the same via Attach() but you must not forget to explicitly set the object state to modified, otherwise no updates occur:

dbContext.Customers.Attach(customer);
dbContext.Entry(customer).State = EntityState.Modified;
dbContext.SaveChanges();

More?

Please leave a comment if you want to share your own experiences.

ASP.NET MVC Web development

MvcPaging 1.0.2

A new version of the MvcPaging component is available via NuGet with the following changes:

So the core library hasn’t changed much, and in all honesty, I think it’s pretty much done. Please leave a reply if you think otherwise.

What did change substantially is the sample application. It was still very much ASP.NET 1.0 with WebForms views. This is now a proper ASP.NET MVC 3 application with Razor views and the default ASP.NET MVC 4.0 template for look & feel.

 Screenshot

The sample application can be found at GitHub.

ASP.NET MVC

Custom Model Binders and Request Validation

In ASP.NET MVC you can create your own model binders to control the way that models are constructed from an HTTP request. For example, if you don’t want any whitespace characters in your model, you can create a custom model binder that trims all whitespace characters when constructing  a model object. You only have to implement the IModelBinder interface and its BindModel method in a class and register it during application startup.

Getting the value from the HTTP request

There are many examples online of how to build a custom model binder. In all these examples you can find a common way of getting a value from the HTTP request:

public class MyModelBinder: IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        if (valueProviderResult != null)
        {
            var theValue = valueProviderResult.AttemptedValue;

            // etc...
        }
    }
}

The code above works nicely and you get protection for potential dangerous request values out of the box. Now let’s assume that we want some potential dangerous values like HTML or XML tags in our model. The recommended way is to add an [AllowHtml] attribute to the model property that may contain HTML and no validation happens for that property. Alternatively, it’s possible to add an [ValidateInput(false)] attribute to the controller action that accepts the model with HTML content, but this turns off validation for all model properties.

A potentially dangerous Request.Form value was detected from the client

Wait a minute! Didn’t we just explicitly say to allow those dangerous values? What’s happening?

It appears that a call to bindingContext.ValueProvider.GetValue() in the code above always validates the data, regardless any attributes. Digging into the ASP.NET MVC sources revealed that the DefaultModelBinder first checks  if request validation is required and then calls the bindingContext.UnvalidatedValueProvider.GetValue() method with a parameter that indicates if validation is required or not.

Unfortunately we can’t use any of the framework code because it’s sealed, private or whatever to protect ignorant devs from doing dangerous stuff, but  it’s not too difficult to create a working custom model binder that respects the AllowHtml and ValidateInput attributes:

public class MyModelBinder: IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        // First check if request validation is required
        var shouldPerformRequestValidation = controllerContext.Controller.ValidateRequest && bindingContext.ModelMetadata.RequestValidationEnabled;

        // Get value
        var valueProviderResult = bindingContext.GetValueFromValueProvider(shouldPerformRequestValidation);
        if (valueProviderResult != null)
        {
            var theValue = valueProviderResult.AttemptedValue;

            // etc...
        }
    }
}

The other required piece is a way to retrieve an unvalidated value. In this example we use an extension method for the ModelBindingContext class:

public static ValueProviderResult GetValueFromValueProvider(this ModelBindingContext bindingContext, bool performRequestValidation)
{
    var unvalidatedValueProvider = bindingContext.ValueProvider as IUnvalidatedValueProvider;
    return (unvalidatedValueProvider != null)
               ? unvalidatedValueProvider.GetValue(bindingContext.ModelName, !performRequestValidation)
               : bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
}