Alexander Beletsky's Development Blog: 2011-08

ELMAH MVC controller released on NuGet

I dedicated some time for that and happy to announce - ELMAH MVC controller released on NuGet.

Due to the latest interest, feedback and changes - it has no sense at all to keep that code just in blog post. In my previous post I promised to create NuGet package for that, so here we are:

PM> Install-Package Elmah.MVC

I simplified code even a little more to avoid changing in routes (in case of Admin area already exists in project).

So just grab it from NuGet now.

Latest version of ELMAH MVC controller

Integrating ELMAH to ASP.NET MVC in right way is blog post I created sometime ago. It appears really popular, because a lot of people had the same issue as me and found solution I created really applicable. It was really cool to receive all that feedback! By the way, elmah.mvc.controller is my first github repository I got pull request!

Especially, I would like to thank to Seba Illingworth and Barry Dorrans who found really nasty issues and helped to fix those.

The controller's code has been moved to github long time ago, but what I see many people just copy-past code from article into their solutions. The code I gave in previous post has been changed drastically, but instead of re-writting original post I decided to create new one.

Latest version of ELMAH MVC controller

So, after all modifications it looks like:

namespace ElmahMvc.Areas.Admin.Controllers {
    class ElmahResult : ActionResult {
        private string _resouceType;

        public ElmahResult(string resouceType) {
            _resouceType = resouceType;
        }

        public override void ExecuteResult(ControllerContext context) {
            var factory = new Elmah.ErrorLogPageFactory();

            if (!string.IsNullOrEmpty(_resouceType)) {
                var pathInfo = "/" + _resouceType;
                context.HttpContext.RewritePath(FilePath(context), pathInfo, context.HttpContext.Request.QueryString.ToString());
            }

            var currentApplication = (HttpApplication)context.HttpContext.GetService(typeof(HttpApplication));
            var currentContext = currentApplication.Context;

            var httpHandler = factory.GetHandler(currentContext, null, null, null);
            if (httpHandler is IHttpAsyncHandler) {
                var asyncHttpHandler = (IHttpAsyncHandler)httpHandler;
                asyncHttpHandler.BeginProcessRequest(currentContext, (r) => { }, null);
            }
            else {
                httpHandler.ProcessRequest(currentContext);
            }
        }

        private string FilePath(ControllerContext context) {
            return _resouceType != "stylesheet" ? context.HttpContext.Request.Path.Replace(String.Format("/{0}", _resouceType), string.Empty) : context.HttpContext.Request.Path;
        }
    }

    public class ElmahController : Controller {
        public ActionResult Index(string type) {
            return new ElmahResult(type);
        }
    }
}

How to use it in my application?

Easy. Install ELMAH by NuGet, in package console

 Install-Package elmah

It is optional (but preferable) to create new Area called Admin. Inside AreaRegistration.cs your should place routing for ELMAH controller:

context.MapRoute(
        "Admin_elmah",
        "Admin/elmah/{type}",
        new { action = "Index", controller = "Elmah", type = UrlParameter.Optional }
    );

Create ElmahController.cs (just from code above) and place to yours Areas/Admin/Controller folder, add file to project. Don't forget to change the namespace according to your project.

Configure ELMAH logging options (Memory, XML, SQL), use Web.Config of this project as example. Run application, and see that:

 /admin/elmah

works.

Optional (but very preferable) is to secure your controller with Authorize attribute:

 [Authorize(Users = "Admin")]
 public class ElmahController : Controller
 {

That's it.

Known issues

One current known issue - if I'm using SqlErrorLog as error log class and press "Download log" button on ELMAH dashboard, you've got empty result. Unfortunately, it does not work now, since issue in ELMAH core that I hope will be fixed in nearest release.

NuGet package for it?

I didn't expect such popularity of that class, but now I seriosly think putting this on NuGet. I'll try to package that as soon as possible.

Inside ASP.NET MVC: IResolver and it's implementations

One of the major changes between MVC2 and MVC3 was introduction of Dependency Injection principles on a level of framework. If you compare, for instance ControllerBuilder.cs from MVC2 and ControllerBuilder.cs from MVC3 you will clearly see the difference. In MVC3 we are no longer create entities directly (through 'new' operator), but instead we delegate that to IResolver interface. IResolver interface itself is extremely simple:

namespace System.Web.Mvc {
    internal interface IResolver<T> {
        T Current { get; }
    }
}

We can just ask the instance of type we would like to resolve. Please also note, that IResolver is internal class, so it is not exposed and you will never use it in application directly.

All major entities of MVC framework (ControllerFactory, Filters, ViewEngines etc.) from now resolved by IResolver implementation class. That improves extensibility of framework very much and introduces new strategy of creation objects.

Implementations of IResolver interface

There are two classes that implements IResolver - SingleServiceResolver and MultiServiceResolver. Primary responsibility of those are delegation call to IDependencyResolver methods GetService and GetServices, respectively.

If they just recalling method of IDependecyResolver class, what's are the purpose of those two classes?

There are 2 purposes I can see:

  1. To provide default type instance in case of type is not resolved by IDependencyResolver.
  2. To create instance only once.

How it works?

Now, let's take a look how it actually works. It is really simple and small, so I'm able to put most of code here.

Construction:

public SingleServiceResolver(Func<TService> currentValueThunk, TService defaultValue, string callerMethodName) {
 if (currentValueThunk == null) {
  throw new ArgumentNullException("currentValueThunk");
 }
 if (defaultValue == null) {
  throw new ArgumentNullException("defaultValue");
 }

 _resolverThunk = () => DependencyResolver.Current;
 _currentValueThunk = currentValueThunk;
 _defaultValue = defaultValue;
 _callerMethodName = callerMethodName;
}

You can see, it receives default factory method, default type instance and the name of caller method (used as additional information in exception).

Here, how ControllerBuilder creates the SingleServiceResolver, for instance:

internal ControllerBuilder(IResolver<IControllerFactory> serviceResolver) {
 _serviceResolver = serviceResolver ?? new SingleServiceResolver<IControllerFactory>(
  () => _factoryThunk(),
   new DefaultControllerFactory { ControllerBuilder = this },
  "ControllerBuilder.GetControllerFactory"
 );
}

Since it implements only one property, current Current:

public TService Current {
 get {
  if (_resolverThunk != null) {
   lock (_currentValueThunk) {
    if (_resolverThunk != null) {
     _currentValueFromResolver = _resolverThunk().GetService<TService>();
     _resolverThunk = null;

     if (_currentValueFromResolver != null && _currentValueThunk() != null) {
      throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, MvcResources.SingleServiceResolver_CannotRegisterTwoInstances, typeof(TService).Name.ToString(), _callerMethodName));
     }
    }
   }
  }
  return _currentValueFromResolver ?? _currentValueThunk() ?? _defaultValue;
 }
}

First, we check the existence of _resolverThunk it would always exist (having value of () => DependencyResolver.Current) for first call of the method. Then, we locking on _currentValueThunk protecting for multiple threads access the same method, same time. Then, we try to resolve given type by asking _resolverThunk() to GetService<TService>().

After that we have an if-statement that I didn't get from the very beginning. Fortunately, MVC project has bunch of good unit tests. As I found the test it turns clear to me. The test called CurrentThrowsIfCurrentSetThroughServiceAndSetter and it's Assert part:

[TestMethod]
public void CurrentThrowsIfCurrentSetThroughServiceAndSetter() {
 // Arrange
 TestProvider providerFromCurrentValueThunk = new TestProvider();
 TestProvider providerFromServiceLocation = new TestProvider();
 TestProvider providerFromDefaultValue = new TestProvider();
 Mock<IDependencyResolver> resolver = new Mock<IDependencyResolver>();

 resolver.Setup(r => r.GetService(typeof(TestProvider)))
   .Returns(providerFromServiceLocation);

 SingleServiceResolver<TestProvider> singleResolver = new SingleServiceResolver<TestProvider>(() => providerFromCurrentValueThunk, providerFromDefaultValue, resolver.Object, "TestProvider.Current");

 //Act & assert
 ExceptionHelper.ExpectException<InvalidOperationException>(
  () => singleResolver.Current,
  "An instance of TestProvider was found in the resolver as well as a custom registered provider in TestProvider.Current. Please set only one or the other."
 );
}

This is really important and says: you should not create same type instance both with IDependencyResolver and factory method! In case of ControllerFactory: you should never provide your implementation of IControllerFactory and in the same time resolve IControllerFactory instance by IDependencyResolver. Same rule for all other types. You should decide how you would like to override default behavior. In MVC3 usage of IDependencyResolver is a preferable.

The code below is wrong:

DependencyResolver.SetResolver(new DummyDependencyResolver());
ControllerBuilder.Current.SetControllerFactory(new DummyControllerFactory());

So, after that _resolverThunk is reset and we no longer ask IDependencyResolver, just returning the resolved value.

MultiServiceResolver is even a little simpler.

public IEnumerable<TService> Current {
 get {
  if (_itemsFromService == null) {
   lock (_itemsThunk) {
    if (_itemsFromService == null) {
     _itemsFromService = _resolverThunk().GetServices<TService>();
    }
   }
  }
  return _itemsFromService.Concat(_itemsThunk());
 }
}

The same, singleton strategy of resolving types and then just concatenating resolved by IDependencyResolver with ones retuned by default factory method. It looks strange, but it is legal here to have types resolved both by IDependencyResolver and factory.

Conclusions

IResolver, SingleServiceResolver and MultiServiceResolver are all internal parts of framework. We are not directly using any of them. They used as kind of bridge between previous (MVC2) object creation strategy and new (MVC3) one. New strategy is using Service Locator (IDependencyResolver). It is important that we should never 'mix' both in the same application. Preferable way is IDependencyResolver.

What's next?

We are going to continues our journey of resolving types and meet IDependencyResolver closer.

Previous Inside ASP.NET MVC: ControllerBuilder class

My application for 10KAppart competition

Recently, I've met really interesting competition by @mixonline called 10K Appart. Due to the rules, you have to create an application total size of which should not be more than 10K zipped content. Moreover, it have to be pure client-side application, utilizing HTML5/CSS3 features for responsible design and open API for gathering data. No frameworks, no 3rd parties. I decided to participate.

I've spent several hours to catch up idea. I was thinking about some application for twitter or gmail, but finally I stopped on github. First of all, github is my favorite service, it has clear and open API. Last year I contributed to javascript github-api, so I knew how to start. Application idea is simple: analyze github account and based on actual achievements (number of repos, forks, issues etc.) assign corresponding badge.

I did it a style of weekend project, started up Friday evening, I've spend 3 hours to complete github API adapter and application logic. As always, hard part was - design.

Even I a bit improved my design skill through this year.. still it is big challenge. I choose light blue color for main color and dark blue as auxiliary. I went with Google Web Fonts that I used before and was happy with results. Playing out with colors and gradients, I came up with such front page:

code

With much help of Sasha we have designed badges part of application. I still not 100% happy, but at least it was quite fast.

code

After application were more or less ready, I put it on temporary hosting asking my dear twitter help me to validate it. I received a lot of great feedback (thanks a lot, guys). After all bugs were fixed, I posted my entry to 10K appart.

I've been waiting about 4 days, to receive an answer. Meanwhile, I've seen that new application are being posted.. but not mine. Finally, they responded to me saying "Sorry, but Google Web Fonts are not allowed". That was actually my bad, but I haven't thought that are treated as 3rd party. Anyway, I had to switch to TypeKit very fast. I didn't get same results as with Web Fonts, but I had no time for finding perfect match and reapplied again.

It finally available here - http://10k.aneventapart.com/Entry/Details/512

I would be happy if you try it, tweet it, comment on site. Sources are placed on github, so If you think to improve design or create new type of badge, you are welcome!

IT Jam 2011 in Odessa

IT Jam is a conference for developers in Ukraine. Highly popularized through the last years now it became the most popular IT events in Ukraine. The slogan of conference is "Meet & Mix" saying it's primary goal is to create good conditions for networking and experience sharing.

I've never been visiting IT Jam before. But this time, I not only visited but have a speech there. Moreover, the company I work to was sponsoring .NET section.. and I got a honor to be a representative there. I've started to prepare on a very short notice, just 5 days before conference.. all of these facts let me a little nervous.

We decieded to go by car, with my great colleagues @korneliuk and @VladAlieks. Having a good company is a key for any trip. I haven't noticed how fast we came to Odessa. We stopped in Odessa's Alpine club where I used to spent great summer days during my rollerblading career. We've got there late evening, so had a time only to install our tent, say hello to the sea and fall asleep.

Next morning we have a breakfast and moved to the place. IT Jam took biggest area in Odessa, Odessa's See Terminal. That was really cool, since there you definitely could feel the spirit of Odessa - sea breeze, sun, ships. Marina Vyshegorodskikh and Alexandra Chudner who opened the event, energized the crowd for the rest of the day.

I've spent most my time mostly in .NET section. IT Jam format of speeches are supposed to be short. That was something that I didn't expect at the begining, so after the schedule been published I realized - it is just impossible to fit everything I want to say in such short period of time. Anyway, I had no option and have to start my speech.


Alexander Beletsky on IT Jam


Olga Didich did a great job helping out all speakers and timekeeping. So, I just step by on scene and started up. As always it's quite hard to describe and show the code for such big crowd, but I tried the best. Of cause, I haven't managed to accomplish all my speech.. but I was really happy that people were contacting me a lot of questions, just after it. We were sitting together with one guy after and I was showing the rest of my presentation just for him :).

As "Meet & Mix" format supposed, I had really nice talks with other developers. Ones, that I worked many years ago.. or ones we've met just recently.. or one's we following each other in tweeter but had no chance to meet offline :). So, @dimapasko, @ChuniMuni, @xpinjection, @chaliy, @antonvidishchev, Dmitry Davydov - guys, it very nice to see you there.. Thanks for your company and great beer-n-talks we had together.

At the evening I've met my old friends from Odessa and all our company moved back to Alpine club, to have a swim, drink and guitar playing on beach for all night. That was just amazing conclusion of that day.

I want to say big thanks, for everyone who involved in organization. Keep doing great job and improve from year to year. And for my friends who were always nearby, supported me and didn't allow to be bored.

Analog of SVN branch switch for Git

Working with Git in SVN based organization is possible and make a lot of benefits. Sources checked out once are now at you local repository, so all you do is commits, rebases and dcommits back to SVN. But sometimes you need to be able to switch to another SVN branch. You need something equivalent to "SVN switch" command inside Git environment.

I’m been trying to switch to new branch, but I found no related information about that. I ended up this solution, I would like to share.

  1. Manually add new configuration into ~/.gitconfig, for new SVN location
  2.     [svn-remote "svn25"]
            url = https://svn.server/branches/branch25
            fetch = :refs/remotes/git-svn-25
    
  3. Fetch changes from svn25
  4.     git svn fetch svn25
    
  5. Checkout that branch
  6.     git checkout git-svn-25
    
  7. Create new “master” branch
  8.     git checkout -b master-25
    
  9. Now, master-25 is your “master” for branch25 SVN branch.

You can merge you previous changes.. and continue to work with master-25 as you worked with usual master.