Where should I call Commit() on my UnitOfWork in a Asp.Net MVC app? And still keep my controllers unit testable.
Do I use a HttpModule? Create a base controller and use OnActionExecuted? Or Global.asax: Application_EndRequest()?
Your controller should look something like this:
[HttpPost]
public ActionResult SubmitOrder(Order o)
{
try
{
repository.Add(o);
unitOfWork.Commit();
}
catch (YourCustomExceptionClass exc)
{
ModelState.AddError(exc.ToString());
}
return View();
}
unitOfWork should be declared at the controller-level as:
IUnitOfWork unitOfWork;
And injected into the ctor of the controller - preferably with DI per HTTP Request.
When you think about it - a unit of work in the context of a web application is usually a HTTP Request.
And a HTTP request is directed to only one action method to perform the work. Of course you have the PRG pattern (redirect to a HttpGet action afterwards) - but there should be only 1 [HttpPost] action call per HTTP request.
Therefore it makes sense to commit the UoW at the action method level.
You should have two implementations of IUnitOfWork:
EntityFrameworkUnitOfWork : IUnitOfWork
InMemoryUnitOfWork : IUnitOfWork
So when unit testing - just inject InMemoryUnitOfWork (which commits changes into a static List<T>, for example)
It sounds like your UI should send the commit call to the domain controller which should then pass the call onto the relevant parties in the domain layer.
Related
We use ASP.Net MVC + Autofac + EF6.
DbContext is wrapped by UnitOfWork. We create it for each http request via Autofac.
We also open transaction for whole http request in UnitOfWork constructor.
The problem is that not all http requests have to be wrapped in to the transaction. Some of them even don't have requests to DB.
We'd like to delay transaction open till the first actual request to DB.
Any ideas how one can do it?
We can override SaveChages and open transaction before save, but select queries will not be executed in transaction this way.
One more problem here: we use global filters from EF Plus for soft removable entities. It works good, but filters initialization for context is rather slow. We'd like to delay it till the first actual request to DB too.
The problem is that your UnitOfWork is injected into controller despite an action being called and therefore its constructor is always called even if you don't need to use it. One solution could be using Autofac lazy injection. In this case UnitOfWork's constuctor is called only when its instance is needed
public class SomeController : Controller {
//..
private readonly Lazy<IUnitOfWork> _unitOfWork;
private IAnotherService UnitOfWork => _unitOfWork.Value;
public SomeController(
//..
Lazy<IUnitOfWork> unitOfWork
)
{
//..
_unitOfWork = unitOfWork;
}
//..
public ActionResult ActionNeedsTransaction()
{
//use UnitOfWork
UnitOfWork.SaveChanges();
return Json(value);
}
}
I am developing an Asp Net MVC client that will use Asp Net Web Api. And I have to decide on how to better design my application. After searching the web for a while I found people suggesting (for example, here) to make MVC action methods asynchronous. I also found out that the main benefit of having asynchronous action methods is scalability of the server, i.e., the server will be able to serve more requests. There is one thing though, the web api I'm consuming has synchronous action methods, and will run on the same server. So my guess is there are no benefits for me to implement asynchronous action methods for my MVC, because even if my MVC action methods are asynchronous and the server will be able to scale from the "MVC point of view" in the end these methods will still consume synchronous Web Api methods, and because of this, the server will "inevitably" run out of its thread pool. Maybe I'm missing something or there are some other benefits of asynchronous action methods?
Here is a very simple sample code I wrote to make you better understand my issue:
This is the web api controller:
public class UsersController : ApiController
{
private readonly IUserService _userService;
public UsersController(IUserService userService)
{
_userService = userService;
}
// As you can see this method is not asynchronous
public User Get(int id)
{
return _userService.GetUserById(id);
}
// some other code
}
This is the Mvc controller, I have two choices how to design my action methods:
public class UsersController : Controller
{
// A) Make simple synchronous action methods
public ActionResult UserPageSync()
{
IUserWebServiceSync userWebServiceSync = new UserWebServiceSync();
User user = userWebServiceSync.GetUserById(1);
return View();
}
// B) Make asynchronous action methods
public async Task<ActionResult> UserPageAsync()
{
IUserWebServiceAsync userWebServiceAsync = new UserWebServiceAsync();
User user = await userWebServiceAsync.GetUserByIdAsync(1);
return View();
}
}
the web api I'm consuming has synchronous action methods, and will run on the same server
This is a highly unusual design. But I'll ignore that.
You can think about it this way: if the MVC actions are synchronous, then they will take 2 threads per request (one for the MVC action, one for the WebAPI action). If the MVC actions are asynchronous, then they will take 1 thread per request (none for the MVC action, one for the WebAPI action). So there's still a clear benefit to doing async on your MVC actions.
I am using EF Core 1.0 (previously known ad EF7) and ASP.NET Core 1.0 (previously known as ASP.NET 5) for a RESTful API.
I'd like to have some unit of work scoped to an http request in such a way that when responding to the HTTP request either ALL the changes made to the DbContext will be saved onto the database, or none will be saved (if there was some exception, for example).
In the past I have used WebAPI2 for this purpose with NHibernate by using an Action filter where I begin the transaction on action executing, and on action executed I end the transaction and close the session. This was the way recommended at http://isbn.directory/book/9781484201107
However now I am using Asp.Net Core (with Asp.Net Core Mvc although this should not be relevant) and Entity Framework which, I understood, already implements a unit of work.
I think having a middleware plugged into the ASP.NET pipeline (before MVC) would be the right way to do things. So a request would go:
PIPELINE ASP.NET: MyUnitOfWorkMiddleware ==> MVC Controller ==> Repository ==> MVC Controller ==> MyUnitOfWorkMiddleware
I was thinking of having this middleware save the DbContext changes if no exception happened, so that in my repository implementations I don't even need to do dbcontext.SaveChanges() and everything would be like a centralized transaction. In pseudocode I guess it would be something like:
class MyUnitOfWorkMiddleware
{
//..
1-get an instance of DbContext for this request.
try {
2-await the next item in the pipeline.
3-dbContext.SaveChanges();
}
catch (Exception e) {
2.1-rollback changes (simply by ignoring context)
2.2-return an http error response
}
}
Does this make sense? Does anybody have any example of something similar? I can't find any good practice or recommendation around this.
Also, if I go with this approach at my MVC controller level I would not have access to any resource ID created by the database when POSTing a new resource because the ID would not be generated until the dbContext changes are saved (later on in the pipeline in my middleware AFTER the controller has finished executing). What if I needed to access the newly created ID of a resource in my controller?
Any advice would be greatly appreciated!
UPDATE 1: I found a problem with my approach to use middleware to achieve this because the DbContext instance in the middleware is not the same as during the MVC (and repositories) lifetime. See the question Entity Framework Core 1.0 DbContext not scoped to http request
UPDATE 2:I haven't yet found a good solution. Basically these are my options so far:
Save the changes in DB as soon as possible. That means saving it on the repository implementation itself. The problem with this approach is that for an Http request maybe I want to use several repositories (i.e: save something in database and then upload a blob to a cloud storage) and in order to have a Unit of Work I would have to implement a repository that deals with more than one entity or even more than one persistance method (DB and Blob Storage), which defeats the whole purpose
Implement an Action Filter where I wrap the whole action execution in a DB transaction. At the end of the controller's action execution, if there are no exceptions I commit chanches to DB but if there are exceptions I rollback and discard the context. The problem with this is that my controller's action may need a generated Entity's Id in order to return it to the http client (i.e: If I get a POST /api/cars I would like to return a 201 Accepted with a location header that identifies the new resource created at /api/cars/123 and the Id 123 would not be available yet since the entity has not been saved in DB and the Id is still a temporary 0). Example in controller's action for a POST verb request:
return CreatedAtRoute("GetCarById", new { carId= carSummaryCreated.Id }, carSummaryCreated); //carSummaryCreated.Id would be 0 until the changes are saved in DB
How could I have the whole controller's action wrapped in a DB transaction and at the same time have available any Id generated by the database in order to return it in the Http Response from the controller? Or.. is there any elegant way to overwrite the http response and set the Id at the action filter level once the DB changes have been commited?
UPDATE 3: As per nathanaldensr's comment I could get the best of both worlds (wrapping my controller's action execution in a DB transaction _ UoW and also knowing the Id of the new resource created even before the DB commits changes) by using code generated Guids instead relying on database to generate the Guid.
As per Entity Framework Core 1.0 DbContext not scoped to http request
I could not use a middleware to achieve this because the instance of DbContext that the middleware gets injected is not the same as the DbContext during MVC execution (in my controllers, or repositories).
I had to go with a similar approach to save the changes in DbContext after the controller's action execution using a Global Filter.
There is no official documentation yet about filters in MVC 6 so if anybody is interested on this solution see below the filter and the way I make this filter global so that it executes before any controller's action.
public class UnitOfWorkFilter : ActionFilterAttribute
{
private readonly MyDbContext _dbContext;
private readonly ILogger _logger;
public UnitOfWorkFilter(MyDbContext dbContext, ILoggerFactory loggerFactory)
{
_dbContext = dbContext;
_logger = loggerFactory.CreateLogger<UnitOfWorkFilter>();
}
public override async Task OnActionExecutionAsync(ActionExecutingContext executingContext, ActionExecutionDelegate next)
{
var executedContext = await next.Invoke(); //to wait until the controller's action finalizes in case there was an error
if (executedContext.Exception == null)
{
_logger.LogInformation("Saving changes for unit of work");
await _dbContext.SaveChangesAsync();
}
else
{
_logger.LogInformation("Avoid to save changes for unit of work due an exception");
}
}
}
and the filter gets plugged into my MVC at Startup.cs when configuring MVC.
public void ConfigureServices(IServiceCollection services)
{
//..
//Entity Framework 7
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<SpeediCargoDbContext>(options => {
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]);
});
//MVC 6
services.AddMvc(setup =>
{
setup.Filters.AddService(typeof(UnitOfWorkFilter));
});
//..
}
This still leaves a question (see UPDATE 2 on my question). What if I want my controller to respond to an http POST request with a 201 Accepted with a Location header that includes the Id of the entity created in DB? When the controller's action finalises execution the changes have not yet been committed to DB therefore the Id of the entity created is still 0 until the action filter saves changes and the DB generates a value.
I am also facing the same issue and not sure which approach to follow.
One of the approach that I used is as follow:
public class UnitOfWorkFilter : ActionFilterAttribute
{
private readonly AppDbContext _dbContext;
public UnitOfWorkFilter(AppDbContext dbContext,)
{
_dbContext = dbContext;
}
public override void OnActionExecuted(ActionExecutedContext context)
{
if (!context.HttpContext.Request.Method.Equals("Post", StringComparison.OrdinalIgnoreCase))
return;
if (context.Exception == null && context.ModelState.IsValid)
{
_dbContext.Database.CommitTransaction();
}
else
{
_dbContext.Database.RollbackTransaction();
}
}
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.HttpContext.Request.Method.Equals("Post", StringComparison.OrdinalIgnoreCase))
return;
_dbContext.Database.BeginTransaction();
}
}
My advice, use dbContext.SaveChanges() in the controller as it is demonstrated in all examples over the web. What you want to do sounds quite fancy and could backfire as you guessed at the end of your post. And IMO, it doesn't make sense.
Regarding your second question/task:
....when responding to the HTTP request either ALL the changes made to the DbContext will be saved onto the database, or none will be saved (if there was some exception, for example).
I think you need something like 'transaction-per-request'. It is just an idea, haven't tested it at all. I just put the code together in this sample middleware:
public class TransactionPerRequestMiddleware
{
private readonly RequestDelegate next_;
public TransactionPerRequestMiddleware(RequestDelegate next)
{
next_ = next;
}
public async Task Invoke(HttpContext context, DbContext dbContext)
{
var transaction = dbContext.Database.BeginTransaction(
System.Data.IsolationLevel.ReadCommitted);
await next_.Invoke(context);
if (context.Response.StatusCode == 200)
{
transaction.Commit();
}
else
{
transaction.Rollback();
}
}
}
Good luck
according to this ASP.NET MVC article I created a Unity of Work class in combination with a generic repository.
I have a lot of model classes as well as always the same controller actions like Create, Update, Delete and so on. So in each controller, the Create action would look like
public ActionResult Create(
[Bind(Include = "CourseID,Title,Credits,DepartmentID")]
Course course)
{
try
{
if (ModelState.IsValid)
{
unitOfWork.CourseRepository.Insert(course);
unitOfWork.Save();
return RedirectToAction("Index");
}
}
catch (DataException)
{
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
return View(course);
}
So my question is: is it possible to create e.g. a "global" ActionResult "Create" in a BaseController, where the right UoW Repository is used according to the entity (or give over the relevant repository of Unity of work class)?
In the specific controller action, I would only like to call this global method like:
return new BaseController().Create(entity)
usually BaseController is an abstract class, and should not be possible to make an instance out of it. I think you should run the Create from specific Controller like this below:
return new CourseController(new CourseRepository()).Create(course);
BaseController should implement a interface like IRepository.Create, and while initialization of specific controller you could pass the right repository - maybe with a help of IoC you could just request CourseController with all Dependencies Injected.
I hope this helps.
i have just started working in MVC and I have one doubt.
Instead of Nonaction method , we can create private method in controller or we can also write method in model and call that from controller.
So , what is the real purpose to use public NonAction method in MVC ?
(I restructured the answer to better address the questions in the comments)
I think, the attribute is here only for better flexibility. As a framework designer, one wants to relax coding constraints off the end user as much as possible. Requirement of not having public non-actions may sound good "in general" but may be too restrictive for some projects. Adding [NonAction] solves their problem (introduced by their bad design though) - and obviously you're not forced to use the attribute, so it's a win-win from a framework designer perspective.
Another reason may be legacy - in the earlier MVC versions only methods marked with [Action] where considered as actions. So when they relaxed the requirement (and all public methods became treated as actions) they kept [NonAction] so that developers won't get too confused.
In general, using NonAction is a bad practice - exactly for the reasons you stated. If something shouldn't be an action, it should not be public in the first place.
Problem with public non-action methods on the controller is that they make people tempted to instantiate your controller and call the method, instead of separating out the common logic:
Compare
public class MyController : IController
{
public ActionResult Foo(long orderId)
{
var order = new OrdersController().GetOrder(orderId); //GetOrder is public
...
}
}
with
public class MyController : IController
{
public ActionResult Foo(long orderId)
{
var order = _orderService.GetOrder(orderId);
...
}
}
The first approach leads to increased coupling between controllers and non-straightforward code in the actions. Code becomes difficult to follow and refactor, and cumbersome to mock/test.
Besides increased coupling, any public non-action method is a security hole - if you forget to mark it with [NonAction] (or, better, change away from public) - because it's treated as normal action and can be invoked externally. I know the original question kinda implies you surely would never forget to attach the attribute if needed, but it's also kinda important to understand what can happen if you would ;) Oh well, and as we're on this, it seems to me that "forgetting the attribute" is more theoretically probable, comparing to "forgetting to make the method private".
Sometimes people say having public non-actions is necessary for unit testing, but again, when something is not an action it most likely can be isolated in a separate class and tested separately. Moreover, even if it's not feasible for whatever reason, marking a method public for testing purposes only is a bad habit - using internal and InternalsVisibleTo is the recommended way.
This kind of situation may be caused by requirements some testing framework such as you need to do unit testing on that method then you to expose it although its a bad design but can't change these had to bear it out.
By default, the MVC framework treats all public methods of a controller class as action methods. If your controller class contains a public method and you do not want it to be an action method, you must mark that method with the NonActionAttributeattribute.
Real purpose to use public NonAction
To restrict access to non-action method to notify MVC framework that given controller method is not action.
When you try to run a method with NonAction attribute over URL you get the error 404 as response to request.
Ref: http://msdn.microsoft.com/en-us/library/dd410269%28v=vs.90%29.aspx
For Detail: http://weblogs.asp.net/gunnarpeipman/archive/2011/04/09/asp-net-mvc-using-nonactionattribute-to-restrict-access-to-public-methods-of-controller.aspx
This is beneficial when the Url are not case sensitive. So that for example if you have the request Home/About this goes to HomeController and About action, as well as hOmE/AbOUT is going to the same controller and same action method.
Like below
public class HomeController:Controller
{
....
public ViewResult About()
{
return View();
}
public ViewResult aBOut()
{
return View();
}
}
The framework can’t determine which about function to call, and throws the exception telling that the call is ambiguous.
Of course one way to fix this problem is to change the action name.
If for some reason you don’t want to change the action name, and one of these function is not an action, then you can decorate this non action method with NonAction attribute. Example:
[NonAction]
public ActionResult aBOut()
{
return View();
}
By default, the MVC framework treats all public methods of a controller class as action methods. If your controller class contains a public method and you do not want it to be an action method, you must mark that method with the NonActionAttribute attribute.
We are using controllers as binding drivers with custom ASP pipeline, each driver is responsible for rendering one section (partial view) of result page. Then we are using public methods like:
[NonAction]
publi int GetOrder()
to resolve sections order on page or other to resolve authorization for current user (e.g. if current section is editable or just read-only).
So you should not restrain yourself to think about Controller as only a way to handle requests but also as a tool to build your custom framework for rendering page. That way we keep our Controllers responsible for exactly one task and we are separating domain concerns.
ASP.NET is highly customizable. Assume you are going to change the default behavior of the framework by overriding the MVC HTTP handler. Maybe you want to customize the logging logic depending on the controller, which is used. Some controllers implement your ILoggingController interface with the method IControllerLogger GetLogger(). For this method you need to write a public non-action method.