-
-
Save ilyapalkin/c82904208bd529814713 to your computer and use it in GitHub Desktop.
"Can I refactor to Model View Query Handler?" answer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class QueryFilterAttribute : ActionFilterAttribute | |
{ | |
public override void OnActionExecuting(ActionExecutingContext filterContext) | |
{ | |
base.OnActionExecuting(filterContext); | |
object query = filterContext.ActionParameters["query"]; | |
Type queryType = query.GetType(); | |
Type modelType = queryType.GetInterfaces()[0].GetGenericArguments()[0]; | |
Type handlerType = typeof(IQueryHandler<,>).MakeGenericType(queryType, modelType); | |
// Here you should resolve your IQueryHandler<,> using IoC | |
// 'Service Locator' pattern is used as quick-and-dirty solution to show that code works. | |
IQueryHandler handler = ComponentLocator.GetComponent(handlerType) as IQueryHandler; | |
object model = handler.Handle(query); | |
filterContext.Controller.ViewData.Model = model; | |
} | |
} | |
[QueryFilter] | |
public class ConferenceController : Controller | |
{ | |
public ActionResult Index(IndexQuery query) | |
{ | |
return View(); | |
} | |
public ViewResult Show(ShowQuery query) | |
{ | |
return View(); | |
} | |
public ActionResult Edit(EditQuery query) | |
{ | |
return View(); | |
} | |
} | |
/// <summary> | |
/// Generic query | |
/// </summary> | |
/// <typeparam name="TResponse">The type of the model to response.</typeparam> | |
public interface IQuery<out TResponse> { } | |
public class IndexModel | |
{ | |
public string A { get; set; } | |
} | |
public class IndexQuery : IQuery<IndexModel> | |
{ | |
public string EventName { get; set; } | |
} | |
public class ShowModel | |
{ | |
public string B { get; set; } | |
} | |
public class ShowQuery : IQuery<ShowModel> | |
{ | |
public string EventName { get; set; } | |
} | |
public class EditModel | |
{ | |
public string C { get; set; } | |
} | |
public class EditQuery : IQuery<EditModel> | |
{ | |
public string EventName { get; set; } | |
} | |
/// <summary> | |
/// All derived handlers can be refactored using generics. But in the real world handling logic can be completely different. | |
/// </summary> | |
/// <typeparam name="TQuery">The type of the query.</typeparam> | |
/// <typeparam name="TResponse">The type of the response.</typeparam> | |
public interface IQueryHandler<in TQuery, out TResponse> : IQueryHandler | |
where TQuery : IQuery<TResponse> | |
{ | |
TResponse Handle(TQuery query); | |
} | |
/// <summary> | |
/// This interface is used in order to invoke 'Handle' for any query type. | |
/// </summary> | |
public interface IQueryHandler | |
{ | |
object Handle(object query); | |
} | |
/// <summary> | |
/// Implements 'Handle' of 'IQueryHandler' interface explicitly to restrict its invocation. | |
/// </summary> | |
/// <typeparam name="TQuery">The type of the query.</typeparam> | |
/// <typeparam name="TResponse">The type of the response.</typeparam> | |
public abstract class QueryHandlerBase<TQuery, TResponse> : IQueryHandler<TQuery, TResponse> | |
where TQuery : IQuery<TResponse> | |
{ | |
public abstract TResponse Handle(TQuery query); | |
object IQueryHandler.Handle(object query) | |
{ | |
return Handle((TQuery)query); | |
} | |
} | |
public class IndexQueryHandler : QueryHandlerBase<IndexQuery, IndexModel> | |
{ | |
private readonly ISession _session; | |
public IndexQueryHandler(ISession session) | |
{ | |
_session = session; | |
} | |
public override IndexModel Handle(IndexQuery query) | |
{ | |
var model = new IndexModel | |
{ | |
A = query.GetType().Name | |
}; | |
return model; | |
} | |
} | |
public class ShowQueryHandler : QueryHandlerBase<ShowQuery, ShowModel> | |
{ | |
private readonly ISession _session; | |
public ShowQueryHandler(ISession session) | |
{ | |
_session = session; | |
} | |
public override ShowModel Handle(ShowQuery query) | |
{ | |
var model = new ShowModel | |
{ | |
B = query.GetType().Name | |
}; | |
return model; | |
} | |
} | |
public class EditQueryHandler : QueryHandlerBase<EditQuery, EditModel> | |
{ | |
private readonly ISession _session; | |
public EditQueryHandler(ISession session) | |
{ | |
_session = session; | |
} | |
public override EditModel Handle(EditQuery query) | |
{ | |
var model = new EditModel | |
{ | |
C = query.GetType().Name | |
}; | |
return model; | |
} | |
} | |
#region ISession and FakeSession to show that dependencies can be injected | |
public interface ISession | |
{ | |
} | |
public class FakeSession : ISession | |
{ | |
} | |
#endregion |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[QueryFilter] | |
public class ConferenceController : Controller | |
{ | |
public ActionResult Index(IndexQuery query) | |
{ | |
return View(); | |
} | |
public ViewResult Show(ShowQuery query) | |
{ | |
return View(); | |
} | |
public ActionResult Edit(EditQuery query) | |
{ | |
return View(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@model WebUI.Controllers.EditModel | |
@{ | |
ViewBag.Title = Model.GetType(); | |
} | |
<h2>@Model.C</h2> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class MvcApplication : HttpApplication | |
{ | |
private readonly IWindsorContainer container; | |
/// <summary> | |
/// Method executing on application start. | |
/// </summary> | |
protected void Application_Start() | |
{ | |
XmlInterpreter xmlInterpreter = new XmlInterpreter( | |
new ConfigResource("castle")); | |
container = new WindsorContainer(xmlInterpreter); | |
container.Register(Component.For<ISession>().ImplementedBy<FakeSession>()); | |
container.Register( | |
Classes.FromThisAssembly() | |
.BasedOn(typeof(IQueryHandler<,>)) | |
.WithService.Base() | |
.LifestylePerWebRequest()); | |
} | |
/// <summary> | |
/// Method executing on application end. | |
/// </summary> | |
protected void Application_End() | |
{ | |
container.Dispose(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@model WebUI.Controllers.IndexModel | |
@{ | |
ViewBag.Title = Model.GetType(); | |
} | |
<h2>@Model.A</h2> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// Generic query | |
/// </summary> | |
/// <typeparam name="TResponse">The type of the model to response.</typeparam> | |
public interface IQuery<out TResponse> { } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class QueryFilterAttribute : ActionFilterAttribute | |
{ | |
public override void OnActionExecuting(ActionExecutingContext filterContext) | |
{ | |
base.OnActionExecuting(filterContext); | |
object query = filterContext.ActionParameters["query"]; | |
Type queryType = query.GetType(); | |
Type modelType = queryType.GetInterfaces()[0].GetGenericArguments()[0]; | |
Type handlerType = typeof(IQueryHandler<,>).MakeGenericType(queryType, modelType); | |
// Here you should resolve your IQueryHandler<,> using IoC | |
// 'Service Locator' pattern is used as quick-and-dirty solution to show that code works. | |
IQueryHandler handler = ComponentLocator.GetComponent(handlerType) as IQueryHandler; | |
object model = handler.Handle(query); | |
filterContext.Controller.ViewData.Model = model; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// All derived handlers can be refactored using generics. But in the real world handling logic can be completely different. | |
/// </summary> | |
/// <typeparam name="TQuery">The type of the query.</typeparam> | |
/// <typeparam name="TResponse">The type of the response.</typeparam> | |
public interface IQueryHandler<in TQuery, out TResponse> : IQueryHandler | |
where TQuery : IQuery<TResponse> | |
{ | |
TResponse Handle(TQuery query); | |
} | |
/// <summary> | |
/// This interface is used in order to invoke 'Handle' for any query type. | |
/// </summary> | |
public interface IQueryHandler | |
{ | |
object Handle(object query); | |
} | |
/// <summary> | |
/// Implements 'Handle' of 'IQueryHandler' interface explicitly to restrict its invocation. | |
/// </summary> | |
/// <typeparam name="TQuery">The type of the query.</typeparam> | |
/// <typeparam name="TResponse">The type of the response.</typeparam> | |
public abstract class QueryHandlerBase<TQuery, TResponse> : IQueryHandler<TQuery, TResponse> | |
where TQuery : IQuery<TResponse> | |
{ | |
public abstract TResponse Handle(TQuery query); | |
object IQueryHandler.Handle(object query) | |
{ | |
return Handle((TQuery)query); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@model WebUI.Controllers.ShowModel | |
@{ | |
ViewBag.Title = Model.GetType(); | |
} | |
<h2>@Model.B</h2> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment