In our application we have CQRS: we have IAsyncCommand with IAsyncCommandHandler<IAsyncCommand>.
Usually the command is processed via Mediator like this:
var mediator = //get mediator injected into MVC controller via constructor
var asyncCommand = // construct AsyncCommand
// mediator runs ICommandValidator and that returns a list of errors if any
var errors = await mediator.ProcessCommand(asyncCommand);
That works fine. Now I noticed that I do a lot of repetitive code in controller actions:
public async virtual Task<ActionResult> DoStuff(DoStuffAsyncCommand command)
{
if (!ModelState.IsValid)
{
return View(command);
}
var result = await mediator.ProcessCommandAsync(command);
if (!result.IsSuccess())
{
AddErrorsToModelState(result);
return View(command);
}
return RedirectToAction(MVC.HomePage.Index());
}
And this patterns repeats over and over in many-many controllers. So for single-threaded commands I've done simplification:
public class ProcessCommandResult<T> : ActionResult where T : ICommand
{
private readonly T command;
private readonly ActionResult failure;
private readonly ActionResult success;
private readonly IMediator mediator;
public ProcessCommandResult(T command, ActionResult failure, ActionResult success)
{
this.command = command;
this.success = success;
this.failure = failure;
mediator = DependencyResolver.Current.GetService<IMediator>();
}
public override void ExecuteResult(ControllerContext context)
{
if (!context.Controller.ViewData.ModelState.IsValid)
{
failure.ExecuteResult(context);
return;
}
var handlingResult = mediator.ProcessCommand(command);
if (handlingResult.ConainsErrors())
{
AddErrorsToModelState(handlingResult);
failure.ExecuteResult(context);
}
success.ExecuteResult(context);
}
// plumbing code
}
And after some plumbing done, my controller action looks like this:
public virtual ActionResult Create(DoStuffCommand command)
{
return ProcessCommand(command, View(command), RedirectToAction(MVC.HomePage.Index()));
}
This works well for sync-commands where I don't need to do async-await patterns. As soon as I try to do async operations, this does not compile, as there is no AsyncActionResult in MVC (or there is and I can't find it) and I can't make MVC framework use async operations on void ExecuteResult(ControllerContext context).
So, any ideas how I can make a generic implementation of the controller action I quoted on top of the question?
Your solution seems overly complex, highly smelly (contains both service location, and other smells) and seems to miss the point of what ActionResults are (command objects themselves, really).
In reality, this is a good example of The XY Problem. Rather than asking about your actual problem, which is refactoring common code in your action methods in an async friendly way, you have instead come up with an overly complex solution that you think solves your problem. Unfortunately, you can't figure out how to make it work, so you ask about THAT problem rather than your real problem.
You can achieve what you want with a simple helper function. Something like this:
public async virtual Task<ActionResult> DoStuff(DoStuffAsyncCommand command)
{
return await ControllerHelper.Helper(command, ModelState, _mediator,
RedirectToAction(MVC.HomePage.Index()), View(command), View(command));
}
public static class ControllerHelper
{
// You may need to constrain this to where T : class, didn't test it
public static async Task<ActionResult> Helper<T>(T command,
ModelStateDictionary ModelState, IMediator mediator, ActionResult returnAction,
ActionResult successAction, ActionResult failureAction)
{
if (!ModelState.IsValid)
{
return failureResult;
}
var result = await mediator.ProcessCommandAsync(command);
if (!result.IsSuccess())
{
ModelState.AddErrorsToModelState(result);
return successResult;
}
return returnAction;
}
public static void AddErrorsToModelState(this ModelStateDictionary ModelState, ...)
{
// add your errors to the ModelState
}
}
Alternatively, you could make it a stateful object and inject the mediator through cascaded dependencies via constructor injection. It's not easy to inject ModelState, unfortunately, so that still needs to be passed as a parameter to the method.
You could also just pass the string for the ActionResults, but since there's no RedirectToActionResult object to new up, you'd have to mess with initializing a RedirectToRoute object and it's just easier to pass the ActionResult. It's also much easier to use the Controllers View() function than to construct a new ViewResult yourself.
You could also use the Func<ActionResult> approach that Sambo uses, which makes it lazy evaluate, so it only calls the RedirectToAction method when necessary. I don't think RedirectToAction has enough overhead to make it worth it.
Seems like an Action is still the best place to handle your logic instead of using an ActionResult.
If the code is duplicated, why not use a base class with a protected helper method...?
public class BaseCommandController : Controller
{
protected IMediator Mediator { get { return DependencyResolver.Current.GetService(typeof (IMediator)) as IMediator; } }
public async virtual Task<ActionResult> BaseDoStuff<TCommand>(TCommand command, Func<ActionResult> success, Func<ActionResult> failure)
{
if (!ModelState.IsValid)
{
return failure();
}
var result = await Mediator.ProcessCommand(command);
if (!result.IsSuccess())
{
AddErrorsToModelState(result);
return failure();
}
return success();
}
private void AddErrorsToModelState(IResponse result)
{
}
}
Your controller's actions are then rendered as...
public class DefaultController : BaseCommandController
{
protected async virtual Task<ActionResult> DoStuff(DoStuffAsyncCommand command)
{
return await BaseDoStuff(command, () => RedirectToAction("Index"), () => View(command));
}
}
Related
I have an extension for ActionResult that adds a toast to TempData when returning a page:
public static IActionResult WithMessage(this ActionResult result, InformMessage msg)
{
return new InformMessageResult(result, msg);
}
and this is InformMessageResult:
public class InformMessageResult : ActionResult
{
public ActionResult InnerResult { get; set; }
public InformMessage InformMessage { get; set; }
public InformMessageResult (ActionResult innerResult, InformMessage informMsg)
{
InnerResult = innerResult;
InformMessage = informMsg;
}
public override async Task ExecuteResultAsync(ActionContext context)
{
ITempDataDictionaryFactory factory = context.HttpContext.RequestServices.GetService(typeof(ITempDataDictionaryFactory)) as ITempDataDictionaryFactory;
ITempDataDictionary tempData = factory.GetTempData(context.HttpContext);
tempData.Put("InformMessage", InformMessage);
await InnerResult.ExecuteResultAsync(context);
}
}
This works well with
return RedirectToPage(etc).WithMessage(etc)
and the like, but fails with
return Page().WithMessage(etc)
and the debugger highlights
await InnerResult.ExecuteResultAsync(context);
saying InnerResult not set to an instance of an object.
Is there a way I can make this work with Return Page()?
Edit for additional info:
I tested what was being sent in as the "InnerResult" and it looks like with Return Page(), everything is null (by design, I'd say, as I do nothing to it before that point):
with RedirectToPage():
With Page():
This is an older question, but I needed functionality like this myself, and dug deep to find the reason.
As you can see from your debugging, the Page method generates a completely blank PageResult. Being as every property is null, calling ExecuteResultAsync on it fails as it obviously can't do anything with all-null values.
The reason Page() otherwise works the rest of the time is due to behind-the-scenes magic in PageActionInvoker, specifically in its InvokeResultAsync method. It will detect that your ViewData and Page are blank and populate them before it, itself, calls the pageResult.ExecuteResultAsync method.
Hence, you can still get your InformMessageResult to work if you do the same work as PageActionInvoker does. Here's how:
public override async Task ExecuteResultAsync(ActionContext context)
{
/* temp data work goes here */
if (InnerResult is PageResult pageResult)
{
var pageContext = context as PageContext
?? throw new ArgumentException("context must be a PageContext if your InnerResult is a PageResult.", "context");
var pageFactoryProvider = pageContext.HttpContext.RequestServices.GetRequiredService<IPageFactoryProvider>();
var pageFactory = pageFactoryProvider.CreatePageFactory(pageContext.ActionDescriptor);
var viewContext = new ViewContext(
pageContext,
NullView.Instance,
pageContext.ViewData,
tempData,
TextWriter.Null,
new Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelperOptions()
);
viewContext.ExecutingFilePath = pageContext.ActionDescriptor.RelativePath;
pageResult.ViewData = viewContext.ViewData;
pageResult.Page = (PageBase)pageFactory(pageContext, viewContext);
}
await InnerResult.ExecuteResultAsync(context);
}
private class NullView : IView
{
public static readonly NullView Instance = new NullView();
public string Path => string.Empty;
public Task RenderAsync(ViewContext context)
{
if (context == null) throw new ArgumentNullException("context");
return Task.CompletedTask;
}
}
The problem I suspect is that Page() and RedirectToPage() inherit from different base classes.
RedirectToPage() as per this documentation. It has the following Inheritance:
Object -> ActionResult -> RedirectToPageResult
This is exposed by some inheritance of the controller. So you're extension of ActionResult is available to be used.
However the Page() method is part of a RazorPages class as per this documentation. So it's inheritance is as follows:1
Object -> RazorPageBase -> PageBase -> Page
Now the Page() method of that class does return a PageResult which looks to inherit from ActionResult as defined here.
So with that in mind I'd suggest casting it to the base ActionResult first, and then using your extension method. Something like this perhaps:
var baseClass = (Page() as ActionResult);
return baseClass.WithMessage(etc);
1 You can see the base type in the second image the OP supplied.
Page() and RedirectToPage() are helper methods for PageResult and RedirectToPageResult respectively. So instead of newing up you call these methods.
When you call Page() it calls ExecuteResultAsync behind the scenes to render the PageResult. At that point, all the properties are null i.e. Page, Model, ViewData etc. As the result is already rendered, So you can't call another ExecuteResultAsync using the WithMessage extension method.
When you call RedirectToPage it issues a 301/302 and generates a new Request that will result in RedirectToPageResult. So the RedirectToPageResult is not rendered yet and you have the option to utilise your WithMessage extension method.
Having said that, I don't think it's possible to utilise the WithMessage when using Page() method, AFAIK.
We have an ASP.Net MVC application for our online store. User has to choose from multiple payment methods in order to buy something. For this we have implemented an abstract factory pattern:
public interface IPaymentServiceFactory
{
IPaymentService GetPaymentService(PaymentServiceEnum paymentServiceType);
}
public interface IPaymentService
{
PaymentSettingsModel GetPaymentSettingsModel();
}
It is used in our Action:
public ActionResult ProcessCart(PaymentDataModel paymentData)
{
var paymentService = _paymentServiceFactory.GetPaymentService(paymentData.PaymentServiceType);
var paymentSettings = paymentService.GetPaymentSettingsModel();
}
The problem occurs when we understand that some payment methods require async calls inside. For example 3rd party online payment service method must be asynchronously called through http for creating payment object on their side. The implemetation:
public class OnlinePaymentService : IPaymentService
{
private readonly IOnlinePaymentServiceApiClient _client;
public async Task<PaymentSettingsModel> GetPaymentSettings()
{
var result = await _client.CreatePaymentAsync();
return result;
}
}
So we come up with a question: How to handle async and sync scenario for different payment methods. We`v decided to make everything async. Updated code:
public interface IPaymentService
{
Task<PaymentSettingsModel> GetPaymentSettings();
}
public async Task<ActionResult> ProcessCart(PaymentDataModel paymentData)
{
var paymentService = _paymentServiceFactory.GetPaymentService(paymentData.PaymentServiceType);
var paymentSettings = await paymentService.GetPaymentSettingsModel();
}
So far so good, but for implementing this for all other payment methods we were forced to use Task.Run:
public class CashPaymentService : IPaymentService
{
public async Task<PaymentSettingsModel> GetPaymentSettings()
{
return await Task.Run(() => new PaymentSettingsModel());;
}
}
As i can understand this creates two different threads for processing Action, which can cause performance issue.
Is there way to avoid such consequences? Is it really so bad to use Task.Run in particular case?
Is it really so bad to use Task.Run in particular case?
Yes, mainly because it's unnecessarily complicating things.
You can return a completed task whose result is a given value using Task.FromResult.
This is completely synchronous:
public class CashPaymentService : IPaymentService
{
public Task<PaymentSettingsModel> GetPaymentSettings()
{
return Task.FromResult( new PaymentSettingsModel() );
}
}
Note that async is missing here - that's possible because it is an implementation detail and not part of the definition of IPaymentService.
I have two controllers that have few same methods:
public class Controller1 : Controller
{
private readonly ITestBL bl;
public Controller1(ITestBL bl)
{
this.bl= bl;
}
[HttpGet]
public ActionResult Method1(string data)
{
using (bl)
{
var res = ...
return Json(res, JsonRequestBehavior.AllowGet);
}
}
[HttpGet]
public ActionResult Method2(string data, int data2)
{
using (bl)
{
var res = ...
return Json(res, JsonRequestBehavior.AllowGet);
}
}
// other methods
}
And the second controller also has those two methods.
Should I create some common controller to keep those methods? So, it will look like this:
public abstract class CommonController: Controller
{
private readonly ITestBL bl;
protected Controller1(ITestBL bl)
{
this.bl= bl;
}
[HttpGet]
public ActionResult Method1(string data)
{
using (bl)
{
var res = ...
return Json(res, JsonRequestBehavior.AllowGet);
}
}
[HttpGet]
public ActionResult Method2(string data, int data2)
{
using (bl)
{
var res = ...
return Json(res, JsonRequestBehavior.AllowGet);
}
}
}
And my Controller1 and Controller2 will be:
public class Controller1 : CommonController
{
private readonly ITestBL bl;
public Controller1(ITestBL bl)
:base(bl)
{
}
// methods
}
Is that the proper way to do that? Do I miss anything or is there a better way?
Should same methods from different controllers be moved to a CommonController?
Yes and you should not use Inheritance. I'm sure there are plenty of people who may disagree, however your example is extremely generic and gives very poor context there is no good reason all controllers need the same code (Inheritance or not). Your questions context has no reason for it to be the case in the OOP realm of Has A vs Is A (Excerpt below).
A House is a Building (inheritance);
A House has a Room (composition);
What it appears you are doing is neither of these.
If your interface was IVehicleEngine and your controllers were FerarriVehicleController and FordVehicleController now it makes sense in a context. In this case each controller should use inheritance, it makes sense.
In my own humble opinions, inheriting from your own controller can be quite difficult in multiple terms. First, it's not intuitive; that is it will become tribal knowledge because it replaces a normal convention that most programmers adhere to (that is deriving from the base MVC controller). Secondly, I've seen it become the one place that everyone decides to add code to (God Object) even though it may not be applicable from some controllers. Thirdly, it makes it difficult to reuse url's that make sense for the derived type but not the base type (/search?searchFor=). There are a number of other considerations that are very specific to MVC because of it's exposure to the web (security etc etc).
Depending on implementation you may also experience difficulty in determining which URL to use under what circumstances.
Is /Controller1/Method1/Data/1 the same as /Controller2/Method1/Data/1 but different from /Controller3/Method1/Data/1? If they are all the same or some are the same and some are different then there is most likely something wrong with the architecture.
Nothing wrong with inheriting from a base controller. As it adheres to the DRY principle. I would go with :
public abstract class CommonController: Controller
{
protected readonly ITestBL bl;
protected Controller1(ITestBL bl)
{
this.bl= bl;
}
[HttpGet]
public virtual ActionResult Method1(string data)
{
var res = ...
return Json(res, JsonRequestBehavior.AllowGet);
}
[HttpGet]
public virtual ActionResult Method2(string data, int data2)
{
var res = ...
return Json(res, JsonRequestBehavior.AllowGet);
}
}
Main differences being.
I removed "using". Like the others have said it's best to let your DI framework decide when to dispose of the injected class.
Make the action results virtual. The inheriting controllers may have the same requirements now, but there is no guarantee that they will stay that way in the future. So declaring them as virtual allows for future changes in scope/requirements as they can be overridden.
I made the injected class "protected" rather then "private" as other methods in both inheriting controllers may need it too.
I am new to MVC and I am trying to create an app using a Repository Service Pattern, I tried my best to follow some tutorials but right now I dont know what's wrong or what ARE wrong in my implementation because I feel there's something wrong though there aren't any errors when building.
my controller
public async Task<JsonResult> Create(string LocationName)
{
Location location = new Location
{
LocationName = LocationName
};
await _LocationService.InsertAsync(location);
var result = await _LocationService.GetAllAsync();
return Json(result, JsonRequestBehavior.AllowGet);
}
This controller receives a string from an ajax post, string is passed correctly to the entity Location {LocationName = LocationName}. After creating a new object of Location, it is passed down to a LocationService:
LocationService
public class LocationService : ILocationService
{
private ILocationRepository _LocationRepository;
public LocationService(ILocationRepository locationRepository)
{
_LocationRepository = locationRepository;
}
public async Task InsertAsync(Location entity)
{
await _LocationRepository.InsertAsync(entity);
}
//other async operations below
}
So the object Location reaches my LocationService then it is passed down again to LocationRepository:
LocationRepository
public class LocationRepository : ILocationRepository
{
private DefaultConnection dbContext;
private DbSet<Location> DbSet;
public LocationRepository()
{
dbContext = new DefaultConnection();
DbSet = dbContext.Set<Location>();
}
public async Task InsertAsync(Location entity)
{
DbSet.Add(entity);
await dbContext.SaveChangesAsync();
}
#region IDisposable
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (dbContext != null)
{
dbContext.Dispose();
}
}
}
#endregion
}
The object Location is inserted but after the SaveAsync, it doesnt go back to my controller to perform the rest of the operation.
Note: Location object is saved in the database, but I need it to go
back to my controller to return a JsonResult of all Locations.
questions
Why is it not getting back to my controller after SaveAsync.
What can be improved / what is wrong with my implementation so I can make it better.
Any help will be much appreciated.
Thank you!
Have you tried calling ConfigureAwait(false) on both dbContext.SaveChangesAsync() and _LocationRepository.InsertAsync(entity)?
There's a chance this deadlock is being caused by the async methods on the libraries not being able to run on the ASP.NET context. ConfigureAway(false) should make every call run in it's own context.
There's a good explanation on async context on Stephen's blog . Check that out to learn more.
I am trying to figure out the best solution for getting error messages in between my service layer and WebApi controllers.
I have a class ModelStateDictionaryWrapper that implements an interface IValidationDictionary
ModelStateDictionaryWrapper
public class ModelStateDictionaryWrapper : IValidationDictionary
{
private readonly ModelStateDictionary modelStateDictionary;
public bool IsValid
{
get
{
return this.modelStateDictionary.IsValid;
}
}
public ModelStateDictionaryWrapper(ModelStateDictionary modelStateDictionary)
{
Enforce.ArgumentNotNull(modelStateDictionary, "modelStateDictionary");
this.modelStateDictionary = modelStateDictionary;
}
public void AddError(string key, string message)
{
this.modelStateDictionary.AddModelError(key, message);
}
}
IValidationDictionary
public interface IValidationDictionary
{
bool IsValid { get; }
void AddError(string key, string message);
}
In my api controller, I am doing this:
public class CategoryController : ControllerBase<ICategoryService>
{
private ICategoryService categoryService;
public CategoryController(ICategoryService categoryService)
{
this.categoryService = categoryService;
this.categoryService.ValidationDictionary =
new ModelStateDictionaryWrapper(this.ModelState);
}
public IEnumerable<CategoryViewModel> Get()
{
return Mapper.Map<CategoryViewModel[]>(this.Service.GetCategories());
}
}
The problem I have with this is I am making a new ModelStateDictionaryWrapper in the constructor of the service and I dont like that.
So I was thinking of changing this to take a factory like so:
public interface IModelStateWrapperFactory
{
IValidationDictionary GetModelStateWrapper(ModelStateDictionary modelStateDictionary);
}
public class ModelStateWrapperFactory : IModelStateWrapperFactory
{
public IValidationDictionary GetModelStateWrapper(
ModelStateDictionary modelStateDictionary)
{
return new ModelStateDictionaryWrapper(modelStateDictionary);
}
}
And then the api controller would look like this (constructor):
public CategoryController(ICategoryService categoryService,
IModelStateWrapperFactory modelStateWrapperFactory)
{
this.categoryService = categoryService;
this.categoryService.ValidationDictionary =
modelStateWrapperFactory.GetModelStateWrapper(this.ModelState);
}
I think I have removed the tight coupling. Does this look like a good solution?
Yes,
You have broken the dependencies between the classes, so you can mock the services during Unit Testing.
I don't know if you have used data annotations and a validation filter or not yet. If not, I would suggest you use them. More details from here http://www.asp.net/web-api/overview/formats-and-model-binding/model-validation-in-aspnet-web-api
An even better approach would be to completely remove this part out of the controller. It should be moved out of the controller, because:
This is effectively a cross-cutting concern and your controller should not be concerned with it; you are violating the Single Responsibility Principle.
Most (if not all) of your controllers will need this construct, which means that you have to repeat it all over the place, making it easy to forget it at some places; you are violating the Don't Repeat Yourself (DRY) principle.
This construct is only possible in the case that the class that needs validation is directly injected into the controller, which might not always be the case. Sometimes you'll need to do validation deeper down the object graph, or you might want to wrap the service with a decorator or interceptor, rendering this approach useless -or at least- extremely troublesome.
There are several solutions to this approach. The first that comes to my mind is to move the setting of the ModelState up, out of the CategoryController's constructor, for instance:
public IHttpController Create(HttpRequestMessage request,
HttpControllerDescriptor descriptor, Type type)
{
var wrapper = new ModelStateDictionaryWrapper();
var controller = new CategoryController(new CategoryService(wrapper));
wrapper.ModelState = controller.ModelState;
return controller;
}
Another -completely different- approach is to to not use the ModelState property at all, but to let your business layer throw specific validation exceptions and catch them higher up the call stack and transform them to Web API status codes.
Throwing exceptions would be a much better approach for the business layer, since this prevents validation errors to go unnoticed. Besides, a design where you fill a dictionary with validation errors is related to Web API and MVC, and is not something that your business layer should be concerned with.
You can do the following in your controller when your BL throws validation exceptions:
public class CategoryController : ControllerBase<ICategoryService>
{
private ICategoryService categoryService;
public CategoryController(ICategoryService categoryService)
{
this.categoryService = categoryService;
}
public HttpResponseMessage Update(CategoryViewModel model)
{
try
{
this.categoryService.Update(model.Category);
}
catch (ValidationException ex)
{
return WebApiValidationHelper.ToResponseCode(ex);
}
}
}
Downside here is of course that your try-catch statements with the calls to the WebApiValidationHelper.ToResponseCode will be duplicated in all your controllers; you'll be violating DRY.
So what you can do instead is extract this code into an DelegatingHandler. My preference would always be to use decorators, but unfortunately Web API makes it impossible to decorate ApiControllers, due to a quirk in its design. So you can inject the following DelegatingHandler into the Web API pipeline:
public class ValidationDelegationHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
try
{
return await base.SendAsync(request, cancellationToken);
}
catch (ValidationException ex)
{
return WebApiValidationHelper.ToResponseCode(ex);
}
}
}
This handler can be injected as follows:
config.MessageHandlers.Add(new ValidationDelegationHandler());