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.
Related
I have a requirement to add a project and translate its description with an external API translation service into several languages (so they exist in the database and it's possible to fetch a project in different languages later). Since translation takes quite some time - I first need to return the API response and then translate description and add additional locale rows to the database.
The db schema looks like this:
DB Context setup:
public class ProjectsContext : DbContext
{
public ProjectsContext(DbContextOptions<ProjectsContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder mb)
{
mb.Entity<Project>().ToTable("Project");
mb.Entity<ProjectLocale>().ToTable("ProjectLocales")
.HasKey(pl => new {pl.ProjectId, pl.Locale});
}
public DbSet<Project> Projects { get; set; }
}
In the Startup class, ConfigureServices method:
services.AddDbContext<ProjectsContext>(options =>
options.UseMySql(envConfig.PROJECTS_DB_CONNECTION_STRING_MASTER));
The models:
public class Project
{
public int Id { get; private set; }
public List<ProjectLocale> ProjectLocales { get; private set; } = new List<ProjectLocale>();
public async Task TranslateDescription(Translator translator, LanguageEnum currentLanguage)
{
ProjectLocales = await translator.Translate(ProjectLocales, currentLanguage);
}
}
public class ProjectLocale
{
public int ProjectId { get; set; }
public string Locale { get; set; }
public string Description { get; set; }
}
In the repository I have the following Add and AddProjectDescriptionTranslation methods:
public void Add(Project project)
{
projectsContext.Projects.Add(project);
projectsContext.SaveChanges();
AddProjectDescriptionTranslations(project);
}
private async Task AddProjectDescriptionTranslations(Project project)
{
await project.TranslateDescription(translator, headers.LanguageEnum);
projectsContext.Projects.Update(project);
projectsContext.SaveChanges();
}
I use Add method in the controller's POST method, and the next row is already returning the added project with the description in the current language. Translator and Headers are injected into my repository class.
The current solution gives me an error (that I can view only if I follow the async method execution with a breakpoint):
Cannot access a disposed object. A common cause of this error is disposing a context that was
resolved from dependency injection and then later trying to use the same context instance
elsewhere in your application. This may occur if you are calling Dispose() on the context,
or wrapping the context in a using statement. If you are using dependency injection, you should
let the dependency injection container take care of disposing context instances.
Object name: 'ProjectsContext'.
Is there any solution to this problem? Or maybe a better approach to achieve the same goal? I need the translations to be saved in the database after the response is given to the user in the current language (I receive the current language project's description from the frontend) to optimize the response time.
Thanks in advance for your time!
It hard to say what you trying to achieve and how you are doing it, so this answer might be useless. I am not sure how you are disposing the context, but you have to make sure you dispose it after all the calls are made.
the most straightforward approach it to have
public async Task Add(Project project)
{
using (var projectsContext= new ProjectsContext())
{
// Perform data access using the context
projectsContext.Projects.Add(project);
projectsContext.SaveChanges();
await AddProjectDescriptionTranslations(project, projectsContext);
}
}
}
private async Task AddProjectDescriptionTranslations(Project project, ProjectsContext projectsContext)
{
await project.TranslateDescription(translator, headers.LanguageEnum);
projectsContext.Projects.Update(project);
projectsContext.SaveChanges();
}
So, not sure if it's the best approach but I was able to solve it the following way:
Added another constructor for ProjectContext and OnConfiguring method:
public ProjectsContext(string connectionString)
{
this.connectionString = connectionString;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (connectionString != null)
{
optionsBuilder.UseMySql(connectionString);
}
}
Added ProjectContextFactory:
public class ProjectsContextFactory
{
private readonly EnvConfig envConfig;
public ProjectsContextFactory(IOptions<EnvConfig> envConfig)
{
this.envConfig = envConfig.Value;
}
public ProjectsContext CreateProjectsContext()
{
return new ProjectsContext(envConfig.PROJECTS_DB_CONNECTION_STRING_MASTER);
}
}
Made the following changes in Add and AddTranslations methods:
public void Add(Project project)
{
projectsContext.Projects.Add(project);
projectsContext.SaveChanges();
AddProjectDescriptionTranslations(project);
}
private async Task AddProjectDescriptionTranslations(Project project)
{
using (var context = projectsContextFactory.CreateProjectsContext())
{
context.Attach(project);
await project.TranslateDescription(translator, headers.LanguageEnum);
context.Projects.Update(project);
context.SaveChanges();
}
}
It allows me to save the project with the current language description and return API response before the description gets translated into other languages and gets saved to the database.
I have read all sorts of posts on this subject but couldn't find the answer to my question.
The general consensus is that I should be creating a context for 1 unit of work (say 1 web page). I have enclosed every method in my Database.cs (see below) with 'using' hence to me - that implies that each time a method from this class is called - a context is created. So if I was to call 2 Methods from Database.cs from the same Action in the HomeController.cs - would that mean that 2 contexts are created?
Would it not be better to declare a private field inside Database.cs like so:
private Entities db = new Entities()
And have each method within the Database.cs class access it? Which approach is the best?
My current implementation (I'm only going to include the method Verify but there are many methods in the Database class):
HomeController.cs
[AllowAnonymous]
public class HomeController : Controller
{
private IDatabase Database;
public HomeController()
{
this.Database = new Database();
}
[HttpGet]
public ActionResult Verify(string id)
{
if (Database.VerifyUser(id))
{
return View();
}
else
{
ViewBag.Error = "There was an error with the verification process";
return View();
}
}
}
Database.cs
public class Database : IDatabase
{
... some other methods ...
public bool VerifyUser(string verificationHash)
{
using (Entities db = new Entities())
{
var userToVerify = db.VerifyUser(verificationHash);
int count = userToVerify.Count();
if (count == 1)
{
return true;
}
else
{
return false;
}
}
}
}
db.VerifyUser(..) - this is a call to a stored procedure
Yes that means there are two instances of DbContext.
The better is to have one instance of DbContext in your Database class and use this instance in all your methods.
public class Database : IDatabase, IDisposeable
{
private Entities db;
public Database()
{
db = new Entities()
}
... some other methods ...
public bool VerifyUser(string verificationHash)
{
var userToVerify = db.VerifyUser(verificationHash);
int count = userToVerify.Count();
if (count == 1)
{
return true;
}
else
{
return false;
}
}
public void Dispose()
{
db.Dispose()
}
}
Then when you finish from Database instance you dispose it and it will dispose the DbContext
public class HomeController : Controller
{
private IDatabase Database;
public HomeController()
{
this.Database = new Database();
}
[HttpGet]
public ActionResult Verify(string id)
{
using(this.Database)
{
if (Database.VerifyUser(id))
{
return View();
}
else
{
ViewBag.Error = "There was an error with the verification process";
return View();
}
}
}
}
BTW: you may prefer to dispose your resources at the controller level. In that case, you don't need to add using statement in your actions
e.g. add this to your controller:
protected override void Dispose(bool disposing)
{
this.Database.Dispose();
base.Dispose(disposing);
}
Yes in your design DbContext created and disposed in every method calls.
Actually, it is not a good solution to put all database operations to a class and create DbContext over and over again. You probably have a problem in future with that class. It might have hundred methods in time and so it is hard to maintain and all entities are not related with each other semantically so it may cause confusion. I think it is a better solution to seperate entity types into classes. For example, you have an users, projects, departments. If we apply my solution to these entities then the uml class diagram will be like this.
All repositories takes a reference to DbContext. It is called Dependency Injection. It means that dbcontext is instantiated once and passes its reference through necessary repositories so there are no context re-creation. Also there is a generic repository which you can put standard procedures.
So you can use repositories like this.
[HttpGet]
public ActionResult Verify(string id){
using(var context = new DbContext())
{
var userRepo = new UserRepository(context);
//Department repository can be used over the same context.
var departmentRepo = new DepartmentRepository(context);
if(userRepo.verifyUser(id)){
return View();
}
}
}
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));
}
}
i have a strange problem, i'm building a Single Page Application with AngularJs and Web API in the server, I'm using Entity framework, i use Code First approach everything is going good, until i want to implement Change password for a user, the updating goes right, but when the user tries to reconnect with his new credentials, entity framework gather the old password !!
public class AuthenticationFilter : ActionFilterAttribute
{
private MyDbRepository repo;
public KhbyraAuthenticationFilter()
{
repo = new MyDbRepository(new MyDbContext());
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
//Login code accessing database by repo object !!
//Here where Entity framework gather old info
}
}
Thats the login Action in SecurityController
[EnableCors("*", "*", "*")]
public class SecurityController : BaseApiController
{
//other actions
[AuthenticationFilter]
[Route("Token")]
[HttpPost]
public IHttpActionResult Login([FromBody]User user)
{
if (user == null)
{
Unauthorized();
}
return Ok();
}
}
Edit
this is where the change pass
[EnableCors("*", "*", "*")]
[KhbyraAuthorizeAttribute]
public class UserController : BaseApiController
{
private int CurrentUserID;
public UserController():base(new KhbyraRepository(new KhbyraContext()))
{
}
//.. other actions
//..
[Route("User/ChangePassword")]
[HttpPost]
public IHttpActionResult ChangePassword([FromBody]ChangePasswordModel model)
{
// here where i save the new password
}
You must instantiate a new repository inside the OnActionExecuting method in AuthenticationFilter. The filter is a singleton so you're keeping one DbContext instance that has the old values cached.
public class AuthenticationFilter : ActionFilterAttribute
{
public KhbyraAuthenticationFilter()
{
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
using(var repo = new MyDbRepository(new MyDbContext()))
{
//Login code accessing database by repo object.
}
}
}
This also makes the code thread safe (which it isn't currently).
My scenario: My application is a Web Api 2 app using a business logic and repository layer for data access. The web application uses ASP.NET Impersonation to login to the database as the user accessing the website (authenticated via PKI). I have several async controller methods. However, when I await on the data access methods, the database call may complete on a different thread which will then access the database under the identity of my application pool which is not allowed to connect to the database.
Example Controller:
public class TestApiController : ApiController {
private IBusinessLogicObject _myBlObject;
public TestApiController(IBusinessLogicObject myBlObject){
_myBlObject = myBlObject; //Populated through Unity
}
public async Task<int> CountMyJobs(string name){
return await _myBlObject.CountMyJobsAsync(name);
}
}
Example Business Logic Class:
public class BusinessLogicObject : IBusinessLogicObject
{
private IGenericRepository<Job> _jobRepository;
public BusinessLogicObject(IGenericRepository<Job> _jobRepository)
{
_jobRepository = jobRepository; //Populated with Unity
}
public Task<int> CountMyJobsAsync(string name)
{
using (WindowsIdentity.GetCurrent().Impersonate())
{
//JobRepository is effectively a DbSet<Job> and this call returns IQueryable<Job>
return _jobRepository.Where(i => i.Name == name).CountAsync();
}
}
}
If I move the using statement into the controller (wrapped around the await), it works fine.
The issue seems to be that because the await is outside of the impersonation context, it does not impersonate the database call (the CountAsync()) and I am unable to open a connection to my database.
The Question:
Is there a way I could write an ActionFilter or some other attribute on my controller method so that the method itself (containing the await call) would be automatically wrapped in the using statement?
merpmerp's answer is going to be problematic in multi-threaded servers. Since there is only one instance of an ActionFilterAttribute per decorated method, two simultaneous requests to the same method will result in usingVariable being overwritten, and only one will end up being disposed.
You'll need to take this a step further and store the ImpersonationContext somewhere in the request context-- e.g. in filterContext.Request.Properties.
I don't believe there is a way to actually wrap a method in a using statement with an attribute, but you could essentially do the same thing by using the OnActionExecuting and OnResultExecuted methods in a custom ActionFilter.
public class IdentityImpersonateActionFilter : ActionFilterAttribute
{
IDisposable usingVaribale;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
usingVaribale = WindowsIdentity.GetCurrent().Impersonate();
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
usingVaribale.Dispose();
}
}
Then you could decorate your methods or your whole controller class with [IdentityImpersonate]
[IdentityImpersonate]
public Task<int> CountMyJobsAsync(string name)
{
//JobRepository is effectively a DbSet<Job> and this call returns IQueryable<Job>
return _jobRepository.Where(i => i.Name == name).CountAsync();
}
You could also access this using variable in your function if you wish
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
usingVaribale = WindowsIdentity.GetCurrent().Impersonate();
filterContext.ActionParameters.Add("parameterName", usingVaribale);
}
And add the parameter to your controller function
[IdentityImpersonate]
public Task<int> CountMyJobsAsync(object parameterName, string name)
{
//JobRepository is effectively a DbSet<Job> and this call returns IQueryable<Job>
return _jobRepository.Where(i => i.Name == name).CountAsync();
}
Hope this helps!
If you want to keep the impersonation the responsibility of the business logic, then you can just do this:
public async Task<int> CountMyJobsAsync(string name)
{
using (WindowsIdentity.GetCurrent().Impersonate())
{
return await _jobRepository.Where(i => i.Name == name).CountAsync()
.ConfigureAwait(false);
}
}