Asp.Net MVC 4 and logging system

Every application must have a logging system trace problem that occur when the system is up and running. In fact, most predictable error should be trapped and handled already inside your code but, in real life, we all know that we aren’t protected against every errors. This is why, it’s important to log errors into a persistence storage like files, database or event viewer of the machine.

I personally like having the log into a database or files because it’s easier to access it if this one is on a remote machine. I found that database is often the easiest way to get every traces because developers usually have access to the database remotely when it might not be the case for the event viewer or files.

Microsoft has since many years published the Enterprise Library (Application Block) which contain a portion that handle logging. Unfortunately, in 2013, this doesn’t to seem to be the favorite way to log even if the Enterprise Library offer a lots of flexibility. Nevertheless, I have used many time the Enterprise Library and it works flawlessly. However, I am using more and more ELMAH logging and really appreciate it. This is mainly because it takes 5 minutes to setup and it handle all unhandled error automatically without the need of any coding.

nuget_elmah

ELMAH installation could be summarized by “Nuget”. This is almost the only thing you will need to do. Open NuGet Package Manager and install ELMAH. This will add to your project the reference required and will modify the web.config. Then, if you need to store the log into your Microsoft SQL server you need to also use Nuget to download the MsSql portion.

From there, you simply need to modify the web.config to give a credential to the database and run a script which create the proper table and stored procedures.

The SQL script are available here to download.
You can download the script for the version of database you need. At this moment, you can download for Microsoft Sql Server, PostgreSQL, MySql, SQLite, MS Access, Oracle.

By default, you can also have access from web page to the log stored into the database (http://yoursite/elmah.axd) if you are running it locally (this prevent users to see the log). If you aren’t using a database, every log will be stored into the memory and will be flushed once the web server is restarted.

Using IDbSetExtensions.AddOrUpdate with Migration Tool fail

Using IDbSetExtensions.AddOrUpdate with Migration Tool fail if you are using a custom IDbSet.

Unable to call public, instance method AddOrUpdate on derived IDbSet type ‘DataAccessLayer.Database.FilteredDbSet`1[Model.Workout]’. Method not found.

The exception above is raised when using : PM> update-database -verbose -force. The class FilteredDbSet, inherit IDbSet and should be able to use the method AddOrUpdate which is pretty useful when seeding data. But, the exception raise and the reason is that it try to get the method definition with a parameter.

    public static void AddOrUpdate<TEntity>(this IDbSet<TEntity> set, params TEntity[] entities) where TEntity : class
    {
      RuntimeFailureMethods.Requires(set != null, (string) null, "set != null");
      RuntimeFailureMethods.Requires(entities != null, (string) null, "entities != null");
      DbSet<TEntity> set1 = set as DbSet<TEntity>;
      if (set1 != null)
      {
        InternalSet<TEntity> internalSet = (InternalSet<TEntity>) set1.InternalSet;
        IDbSetExtensions.AddOrUpdate<TEntity>(set1, IDbSetExtensions.GetKeyProperties<TEntity>(typeof (TEntity), internalSet), entities);
      }
      else
      {
        Type type = set.GetType();
        MethodInfo method = type.GetMethod("AddOrUpdate", new Type[1]
        {
          typeof (TEntity[])
        });
        if (method == (MethodInfo) null)
          throw System.Data.Entity.Resources.Error.UnableToDispatchAddOrUpdate((object) type);
        method.Invoke((object) set, (object[]) new TEntity[1][]
        {
          entities
        });
      }
    }

Instead, we will call the GetMethod without the second parameter.

public static void AddOrUpdate<TEntity>(this IDbSet<TEntity> set, params TEntity[] entities) where TEntity : class
{
	var set1 = set as DbSet<TEntity>;
	if (set1 != null)
	{
		System.Data.Entity.Migrations.IDbSetExtensions.AddOrUpdate(set,entities);
	}
	else
	{
		Type type = set.GetType();
		MethodInfo method = type.GetMethod("AddOrUpdate");

		if (method == null)
			throw new Exception("");
		var data = new object[entities.Length];
		for (int i = 0; i < entities.Length; i++)
		{
			data[i] = entities[i];
		}
		method.Invoke(set, data);
	}
}

Also, you can see that we call Invoke by passing a single array of object. This is required to be able to call the method correctly.

The trick is to create the extension and to use it instead of IDbSetExtension and you will be able to

How to add custom Data Annotation attribute to your property in Asp.Net MVC

In many scenarios the ViewModel will need to provide to the View some additional information could be useful. The case of having an UIHint attribut with the conjunction of this additional information is probably the situation where most people will face at some point.

	[DoSomething]
	public MyClass MyProperty { get; set; }

Let say you have a template that display multiple information from your view model (in the example above “MyClass”). If this one require to display something more (or less) depending of who use it, and that the view model know this information, the only way to pass this information is by data annotation.

Let’s base the theory on the following example.

	[DisableShape("Heavy")]
	[UIHint("ShapeSelector")]
	public Shape TopShape { get; set; }
	
	[UIHint("ShapeSelector")]
	public Shape BottomShape { get; set; }

The view model class has two properties which define 2 shapes. One must be selected from a list of shape but only accept light shape while the other require to have strong shape. We could create two templates but we could also create a simple template and allow to disable some shape. This is the case of the property “TopShape” where we will disable all heavy shape but keep everything selectable for the “BottomShape”.

The first thing to keep in mind is that we will change “ModelMetadataProviders” of MVC to use a custom one when we will be able to add multiple attribute for the whole application. Since we do not want to bind a single attribute we will create a custom meta data provider.

public class CustomModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
	protected override ModelMetadata CreateMetadata(
		IEnumerable<Attribute> attributes,
		Type containerType,
		Func<object> modelAccessor,
		Type modelType,
		string propertyName)
	{
		var modelMetadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
		attributes.OfType<MetadataAttribute>().ToList().ForEach(x => x.Process(modelMetadata));
		return modelMetadata;
	}
}

This code lets you have multiple attributes of type “MetadataAttribute”.

public abstract class MetadataAttribute : Attribute
{
	public abstract void Process(ModelMetadata modelMetaData);
}
}

As you can see, it’s simply an abstract class that lets you define a Process method which is executed in the CreateMetadata method.

From there, you can define what parameter you want for your custom attribute.

public class DisableShapeAttribute : MetadataAttribute
{
	public bool TypeShape { get; set; }
	public DisableShapeAttribute(string type)
	{
		TypeShape = type;
	}

	public DisableShapeAttribute()
	{
		TypeShape = "";
	}

	public override void Process(ModelMetadata modelMetaData)
	{
		modelMetaData.AdditionalValues.Add("DisableShape", TypeShape);
	}
}

The last step is to register the CustomModelMetadataProvider that loop every MetadataAttribute. This is done via the Global.asax.cs, inside the Application_Start method.

ModelMetadataProviders.Current = new CustomModelMetadataProvider();

From here you can read the attribute from your view or template.

var attr = ViewData.ModelMetadata.AdditionalValues.SingleOrDefault(x => x.Key == "DisableShape").Value;
var attrValue = attr != null && (string)attr;

Entity Framework and the error The DELETE statement conflicted with the REFERENCE constraint.

Entity Framework can raise an error concerning a conflict with reference when deleting an entity. One of this error is the following one.

The DELETE statement conflicted with the REFERENCE constraint.

To solve this issue we need to delete cascade instead of a simple remove. We have seen in a previous post how to use delete in cascade with Entity Framework.

In short, you have to specify the many side to the other side (required or optional) and then specify the delete cascade statement with the true parameter.

...HasMany(e => e.ParentDetails)
   .WithOptional(s => s.Parent)
   .WillCascadeOnDelete(true);

The object cannot be deleted because it was not found in the ObjectStateManager

It means that the entity is not attached to the database context (DbContext). You need to attach first the entity to the IDbSet of the DbContext. From here, you can remove the entity.

if (!_set.Local.Contains(entity))
{
    _set.Attach(entity);
}
_set.Remove(entity);

That’s it! We check if the entity is already attached. If it is, then we do not need to do anything. Otherwise, we attach. Attaching will take the primary key of the entity and delete this one even if it’s not fully loaded. The code above could be in a Remove method.

How to bind a collection of Javascript items to a abstracted Asp.Net MVC collection

This scenario is plausible in multiple business domain. Let say that you have a collection that is built from an external service that your Javascript need to send back to the server or even simpler, let just say that you have a Javascript grid that when you save you take all rows of your table and send it back to the server but this one has a model which is a collection of Interface. How you can bind everything back together?

First, let’s take some minutes to understand the mecanism. The example of a the collection is simpler to understand. We have a Model that is bound to the View and the collection is ICollection. Having to create a table is a simple matter of looping the collection and display the properties needed of the interface to the UI.

For example here is what could be the Model:

    UIHint("MyTableTemplate")]
    public readonly ICollection<IMyInterface> MyCollection;

The MyTableTemplate simply loop the collection and display everything inside a TABLE, with multiple TR and TD. When it’s the time to save back everything to the server, we need to send back the collection which could have changed via Javascript. Rows can have been deleted, and some added. How to send back this table to the Asp.Net server? Simply by using serialization. On the submit, we need to hook the click even and store the table serialized into an hidden field. The hidden field must have the same name of the Model bound. In our case, we will have an hidden field with the name “MyCollection”. The code below show you how to do it generically, by having the Template using the information about the name of the property and use it for the hidden field.

@{
    var controlPropertyName = ViewData.TemplateInfo.HtmlFieldPrefix;
}
<input type="hidden" value="" name="@controlPropertyName"/>

Having the same name for the hidden field and the model property let Asp.Net MVC know where to map the information.

The Javascript invoked into the serialization is quite simple. It takes all rows and you create a Javascript object that contains the info. The code below display how to serialize with Javascript 2 cells per rows. As you can see, a “data-key” was set by the template to the row to have the unique identifier. This let us know that this row is not new because new row won’t have any id. The deserialization will put the default value for your key at the deserialization time.

var obj = [];
$('#YouTable tbody tr').each(function () {
	var tempo = {};
	tempo.PropertyKey = $(this).attr('data-key');
	tempo.Property1 = $(this).find('td').eq(0).html();
	tempo.Property2 = $(this).find('td').eq(1).html();
	obj.push(tempo);
});
$('#YourHiddenField').val(JSON.stringify(obj));

Second, let’s see what happen. Asp.Net MVC will try to bind. In fact, it should crash and it’s logic because we try to bind to an interface. What we need to do is to create a ModelBinder and handle this specific case. Since you should know which concrete type is used for this case, when deserializing you simply need to specify to which concrete type the deserializer must instanciate.

The first step is to create a class that inherit from IModelBinder. This will give you the BindModel method.

public class MyInterfaceTypeModelBinder:IModelBinder
{
	public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
	{
		var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
		var modelState = new ModelState	{Value = valueResult};

		MyInterface actualValue = null;
		try
		{
			actualValue = JsonConvert.DeserializeObject<MyInterface>(valueResult.AttemptedValue);
		}
		catch (FormatException e)
		{
			modelState.Errors.Add(e);
		}
		bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
		return actualValue;
	}
}

We also need to register the ModelBinder in the Global.asax.cs inside the ApplicationStart method.

ModelBinders.Binders.Add(typeof(IMyInterface), new MyInterfaceTypeModelBinder());

In the case that the IMyInterface would have some property which were interface too, you may need to specify to the deserializer to what type to map them. Here is an example.

public class MyInterfaceTypeModelBinder:IModelBinder
{
	public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
	{
		var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
		var modelState = new ModelState	{Value = valueResult};

		MyInterface actualValue = null;
		var settings = new JsonSerializerSettings();
		settings.Converters.Add(new MyOtherInterfaceTypeConverter());
		try
		{
			actualValue = JsonConvert.DeserializeObject<MyInterface>(valueResult.AttemptedValue, settings);
		}
		catch (FormatException e)
		{
			modelState.Errors.Add(e);
		}
		bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
		return actualValue;
	}
}
public class MyOtherInterfaceTypeConverter : JsonConverter
{
	public override bool CanConvert(Type objectType)
	{
		return (objectType == typeof(IMyOtherInterface));
	}

	public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
	{
		return serializer.Deserialize<MyOtherInterfaceConcrete>(reader);
	}

	public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
	{
		//... to be done if we care about serialization...
	}
}

From here, the model binder of Asp.Net MVC will use your model binder for your type and sub type used in the process. This whole post has been used Json Newton library for deserializing the Javascript JSON object.

How to find what security group you belong in Windows 7?

This is a short blog entry that I write more as a reminder to know how to check in which group I belong in active directory while logged into a Windows 7 operating system.

gpresult /R

infoGroup
You can also search by using the pipe find method.

gpresult /R | find "Admin"

This will let you know if you belong to the Admin group. This can be handful in some system that you are developing and some right has been set. This way, you can confirm if you are really into a group or not.

The name model does not exist in current context with Asp.Net MVC using Area

The name ‘model’ does not exist in current context. This is the error you can get in a view if you create the first view of an area. How come the framework do not understand the command @model? Well, every area must have a web.config that will contains the code that will tell .Net to use the Razor syntax, which contain the model.

errorWebConfigMissing

  <system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <pages pageBaseType="System.Web.Mvc.WebViewPage">
      <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Routing" />
      </namespaces>
    </pages>
  </system.web.webPages.razor>
 

This error is often present when the area has been created by using “New Folder” instead of “New Area”. Nevertheless, it’s quite simple to solve with the web.config inside the folder.

How to know which button submit a form to an Asp.Net MVC controller

You may want to have multiple button that submit your form and do something different in the action of your controller depending of which button has been used.

An example that can raise is that you want to be able to create a new entity form the view but also be able to create in batch. One button will insert the entity into the database and return into the edit mode of the new added entity while a second button can simply reset the form to let you insert a new one.

The secret is that the submit button is also an input which can have a name and a value. You simply need to have the same name and two different values.

<button type="submit" name="ActionSave" value="insert">Save</button>
<button type="submit" name="ActionSave" value="insertAndContinue">Save and continue</button>

You can from here change your view model to have a property ActionSave (string) or you can go directly into the Form collection.

If you are using the Form Collection, the action inside your controller will look like this:

if (Request.Form[CommandButtonName] == SaveAndContinue)
{
  // ...
}
else...

As you can see, you will need to define 3 constants. One for the command button name, one for the Save and one for the SaveAndContinue.

Otherwise, if you are using the ViewModel option, you need to check the value directly from the view model posted but also have 2 constants which will be Save and SaveAndContinue.

if (model.Action == SaveAndContinue) {
  // ...
}