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 { getset; }

        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 { getset; }

        public Exception TheException { getset; }
    }

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<stringstring>> valuePairs)
        {
            //throw new NotImplementedException();
        }    

        public const string SECTION_NAME = "mysettings";

        ...., etc

        public bool IsShowErrorMessage { getset; }
    }

+ 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.

8 Comments

  • From your example, it looks like you could do it with an interface.

  • Can you not just put the MySettings file in a Shared.dll (or something) and reference it from both projects? It seems that both projects actually depend on that class and therefore it is a shared dependency.

    Paul

  • @Andrew yes, but in the base interface for MySettings is not have IsShowErrorMessage field inside its contract. Some case we will not have this field in base contract. Same with interface in Php, maybe not have people to use it :D

    @Paul That's right. But some situation, we don't want to separate it to one more assmbly. If 2 assemblies are using one class, it should be put in framework and shared for them. In this case, I just keep it simple, so I used dynamic keyword for work with it.

  • Its up to you to create the interface and to require the implementation to implement it.
    Unless you want to throw away type safety when you don't really need to.

  • Why isn't settings in the web infrastructure project in the first place?

  • I think the dynamic and all the other stufg that are late bound is very bad for us. Sure it saves us some work but it makes us create code that the compiler cant help us maintain.

    In general all late bound code (resolved at runtime) as with FindControl and LoadControl is not good news in my world. I would try to avoid it as much as possible.

  • You are right. Maybe dynamic make all things became un-managed. Really dynamic is not good with static language like C#, and everyone are familiar with static contract (interface, abstract class). Maybe I should try to avoid dynamic keyword as much as possible. If we use DLR in the future, I think we will be easy to use dynamic. Now CLR and DLR is living in a boat, look like very terrible. Thanks for all of you. All your comments will make me clear about my solution and improve it in next post.

  • You should avoid the idea of "use it because you can" and try to only use it when it is the most appropriate (it was added for a reason) thing to use.

    :)

Comments have been disabled for this content.