dynamic, Why not?
In these days, people begin to expertise some new features in .NET 4.0. And I am same to them as well. One of features I like and write to this post is dynamic keyword. It is not new, at least in PHP, Python, Ruby... But in .NET world, I think it is new and ship to .NET 4.0 as a default. And some of projects are ported to .NET based on DLR as IronPython, IronRuby. We can use dynamic keyword in anywhere in our project. How do you think about it? So dynamite, isn’t it? :D. Some of people are didn’t like it, some else are love it. How about you? With me, I only try to utilize a new feature in .NET 4.0 for make my work is easier.
Today I obstacle issue when I try to implement an error management in my application. All things will not be hard to get if I didn’t separate all base classes to one assembly and try to reference it from my ASP.NET MVC solution. It is meaning all base controller, base view model and some of helpers, extensions are live in one assembly (called it was WebInfrastructure). And try avoiding acyclic dependency between WebInfrastructure and Web; certainly we will only reference WebInfrastructure from Web and no reverse reference direction from Web in WebInfrastructure. And now if we have one class MySettings in Web and want to the WebInfrastructure can use it. How can we achieve this? This is a place that the dynamic come to.
In WebInfrastructure project, I have
+ AuthorizedController
[Authorize]
[HandleError]
public class AuthorizedController : Controller
{
public AuthorizedController(dynamic mySettings)
{
MySettings = mySettings;
}
......, etc
/// <summary>
/// Gets or sets the settings.
/// Its should be dynamic because this class inside the Infrastructure project that not reference to Web project
/// so it cannot get MySetting from this class
/// </summary>
/// <value>The settings.</value>
protected dynamic MySettings { get; set; }
protected override void OnException(ExceptionContext filterContext)
{
if (filterContext == null)
return;
// Get exception from filter context
var ex = filterContext.Exception ?? new Exception("No further information exists.");
filterContext.ExceptionHandled = true;
var data = new ErrorViewModel();
if (MySettings != null)
{
var isShowErrorMessage = MySettings.IsShowErrorMessage;
if (isShowErrorMessage)
{
data.ErrorMessage = HttpUtility.HtmlEncode(ex.Message);
data.TheException = ex;
}
else
{
// TODO: try to use log4net to log error here
// LogException(ex);
}
}
filterContext.Result = View("Error", data);
}
}
+ ErrorViewModel
public class ErrorViewModel
{
public string ErrorMessage { get; set; }
public Exception TheException { get; set; }
}
In Web project
+ MySettings, it is simple, and just read the config from web.config
public class MySettings : ISectionConfiguration
{
public void Add(string sectionName, string sectionValue, List<KeyValuePair<string, string>> valuePairs)
{
//throw new NotImplementedException();
}
public const string SECTION_NAME = "mysettings";
...., etc
public bool IsShowErrorMessage { get; set; }
}
+ Error view
<asp:Content ID="errorTitle" ContentPlaceHolderID="TitleContent" runat="server">
Error
</asp:Content>
<asp:Content ID="errorContent" ContentPlaceHolderID="MainContent" runat="server">
<h2>
Oops: The system got a critical error. Please contact with system administrator
for resolve this error.
</h2>
<% if (!string.IsNullOrEmpty(Model.ErrorMessage))
{%>
<div>
<h3>
Error message:
</h3>
<p>
<%= Model.ErrorMessage%>
</p>
</div>
<%
}%>
<% if (Model.TheException != null)
{%>
<div>
<h3>
Stack trace:
</h3>
<p style="color: #ff0000;">
<%= Model.TheException.StackTrace %>
</p>
</div>
<div>
<h3>
Source of error:
</h3>
<p>
<%= Model.TheException.Source %>
</p>
</div>
<%
}%>
</asp:Content>
+ Controller
public class HomeController : AuthorizedController
{
public HomeController(MySettings mySettings)
: base(mySettings)
{
}
public ActionResult Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About()
{
return View();
}
}
Notes: We used Unity for IoC container in this post. so its configuration look like this:
var mySettings = SectionConfiguration.GetInstance<MySettings>(MySettings.SECTION_NAME);
ObjectFactory.RegisterInstance(mySettings);
And in run-time, Unity will inject all dependency instances into constructors that have most parameters. As here is
public HomeController(MySettings mySettings)
: base(mySettings)
{
}
Because I need the IsShowMessageError fields in MySettings, but I cannot reference it from WebInfratructure. So I must use the dynamic at this layer for MySetttings, this concrete implementation will be recover when app started (run-time). It’s really cool, isn’t it? But sometimes, I think it is violate the acyclic dependency. I don’t know. So I really love to hear a feedback from you.