Avoid using HttpContext in controller actions to make testing much easier. Therefore all inputs to an action needs to be passed as parameters. In my new REST framework that builds on ASP.NET MVC I have created some useful model binders to make this easy.
[ResourceUriTemplate("")]
public class RootUri : ResourceUri
{
public ResourceResponse Get([HttpCookie] string visited, [AppSetting] int visitTimeout)
{
...
}
}
The HttpCookieAttribute looks for a cookie called "visited". The AppSettingAttribute looks in web.config for an appSetting with the key "visitTimeout". The method is now easy to test and has very readable definition. :)
Both attributes will cast the raw string found into the required type by using a TypeConverter.
The AppSettingAttribute constructor can also take a key name if you want something different from the parameter name.
The code is in SubVersion, but I'll repeat some here to show just how easy it was:
namespace Snooze
{
public class AppSettingAttribute : CustomModelBinderAttribute
{
public AppSettingAttribute()
{
}
public AppSettingAttribute(string key)
{
_key = key;
}
string _key;
public override IModelBinder GetBinder()
{
return new AppSettingModelBinder(_key);
}
}
public class AppSettingModelBinder : IModelBinder
{
public AppSettingModelBinder(string key)
{
_key = key;
}
string _key;
public ModelBinderResult BindModel(ModelBindingContext bindingContext)
{
string setting = WebConfigurationManager.AppSettings[_key ?? bindingContext.ModelName];
object value;
if (bindingContext.ModelType == typeof(string))
{
value = setting;
}
else
{
value = TypeDescriptor.GetConverter(bindingContext.ModelType).ConvertFromString(setting);
}
return new ModelBinderResult(value);
}
}
}