Two dbcontext for the same database - asp.net-core

I have a solution with the following two projects:
Razor Class Library
ASP.NET Core web application
In the class library I have a dbcontext like this:
public partial class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, string>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Customer> Customers { get; set; }
}
In the web application I register the dbcontext as a service using the following lines in my Startup.cs file
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("ApplicationDbContextConnection")));
At this point I can use the dbcontext in both projects. Now, without changing the class library I want to define new tables for the same database so I created a new dbcontext in the web application project which inherits from the one that I have in the class library.
public class ExtendedApplicationDbContext : ApplicationDbContext
{
public ExtendedApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
public DbSet<Product> Products { get; set; }
}
I update my Startup.cs file so that I will register the new dbcontext as well so that I will be able to use the Products table in the web application.
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("ApplicationDbContextConnection")));
services.AddDbContext<ExtendedApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("ApplicationDbContextConnection")));
Now I can use ApplicationDbContext in both projects but when I try to use the ExtendedApplicationDbContext in the web application, something strange happens.
I can read the data but all the changes that I make do not update the database.
I try to explain it but I can not find a way to solve the problem.
Can someone help me understand what is wrong with my code?

EF contexts keeps an object cache and internal change-tracking. Having two separate contexts referencing the same database will inevitably lead to sync issues which will then cause one context to clobber what the other context is doing and vice versa. In short, you should have one and only one active context per database.
I specify active because it's okay to use "bounded" contexts, where you'd have multiple contexts that do in fact connect to the same database, but such contexts should only then deal with a subset of the objects in the database, with no overlap. For example, you might have one context for working with Customers and one for working with Products, but there should then be no cross-over between the two, i.e. the "Products" context should not in any way (even by just mere relation) reference a customer, and vice versa.
Long and short, this is not the correct path. For one, neither the RCL nor the web application should have the context. It should be in a different class library that can then be shared between the two other projects. Also, the web application layer should not make any schema changes to the data layer, as that data layer is being used by other things. That's a good way to shoot yourself in the foot. Keep the data layer stuff with the data layer.

Related

Unable to create a View in ASP.NET Core MVC

I am working on an ASP.NET Core 7.0 MVC app. I have created a data access layer using EF Core 7.0 with a database-first approach. I was trying to create a Razor view through the "AddView" option from the controller for the "Create" process.
However, I am getting this error:
This is how I inject my DbContext:
builder.Services.AddDbContext<NorthwindContext>(options => options.UseSqlServer(
builder.Configuration.GetConnectionString("DefaultConnection")));
I am new to ASP.NET Core. It looks like I have to pass additional options in the Program.cs file. I did a Google search, but couldn't find any help!
If I create the view manually it might work. However, I would like to create it through the scaffolding process.
This is my NorthwindContext code:
After removing the parameterless constructor as per Neil I am getting the new error:
More specifically to my comment, the AddDbContext registers the context class in the asp.net core DI container so it can be provided whenever any class or process wants an instance of the DbContext.
The view generator will want that. However, if the DI container find a parameterless constructor it will use that first, and therefore not use the constructor that passes in the options.
The outcome is a context is provided that does not have the "UseSqlServer" options set.
Hence the error that a database provider has not been configured.
Remove that parameterless constructor from the DbContext and you should be good to go.
The latest error indicates the constructor requires an object of type DbContextOptions.But the injector cannot create the instance.
You could try with the parameterless constructor and configure the options in OnConfiguring method
And the picture you've shown indicates you've seprated Modes from your MVC projects,Make sure you've setted the right startup project(right click on your solution -- Set startup projects) and configrue which projects would contain the migration classes
public class SomeDbContext : DbContext
{
public SomeDbContext()
{
}
public DbSet<SomeEntity> SomeEntity { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("connectionstring", b => b.MigrationsAssembly("MVCProj"));
}
}
Regist it as below:
services.AddDbContext<SomeDbContext>();
If you still got the error,please upload the minimal codes that could reproduce the error

Configuring DI container for global filters with services in their constructors

I have a site using SimpleInjector and MVC, and I'm trying to determine where I'm going wrong architecturally.
I have my DI container being set up:
public static class DependencyConfig
{
private static Container Container { get; set; }
public static void RegisterDependencies(HttpConfiguration configuration)
{
*snip*
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters, Container);
}
}
And my RegisterGlobalFilters looks like this:
public static class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters, Container container)
{
filters.Add(new HandleErrorAttribute());
filters.Add(container.GetInstance<OrderItemCountActionFilterAttribute>());
if (container.GetInstance<ISiteConfiguration>().ConfiguredForExternalOrders)
{
filters.Add(container.GetInstance<StoreGeolocationActionFilterAttribute>());
}
filters.Add(container.GetInstance<StoreNameActionFilterAttribute>());
}
}
The store can take orders (through this website) at in-store kiosks or online from home. External orders would need to geolocate to display information to the customer regarding their closest store. But this means I have to use the container as a service locator in my global filters, which means I have to hide the call to the global filters in my DI container. This all seems to me like an anti-pattern or that there should be a better way to do this.
There is no real issue with the way you are configuring the container and calling the container to resolve the Filter instances, as long as all of this work is being done in the composition root.
The underlying problem as I see it is using Attributes in manner they were not intended to be used. Useful reads on this subject are Steven's post on Dependency Injection in Attributes: don’t do it! and Mark Seemann's post on Passive Attributes. If you were to follow the suggestion in these posts I think you'd find you end up with code you are much happier with.
Also see this recent question raised by Steven here regarding the singleton nature of MVC attributes.
After a bit of discussion with a system architect, we came to the (embarrassingly simple) conclusion that the best answer for our architecture would be to create two Register functions in our DI container - one called RegisterCorporateWebSiteDependencies() and another RegisterStoreWebsiteDependencies().
The natural extension of that is to also have 2 global filter configs called after dependency composition, (again) one for RegisterCorporateGlobalFilters() and one for RegisterStoreGlobalFilters().
This results in one overall if statement running the registers ex:
if (Convert.ToBoolean(ConfigurationManager.AppSettings["IsCorporate"]))
{
DependencyConfig.RegisterCorporateWebSiteDependencies(GlobalConfiguration.Configuration);
}
else
{
DependencyConfig.RegisterStoreWebSiteDependencies(GlobalConfiguration.Configuration);
}
Which is much more straightforward, and removes the logic from the other locations where it can be confusing.

Using RIA Domain Services how to refresh client generated code after making changes to EF

I am working on a N-tier Silverlight 4.0 solution using WCV RIA services, Domain Services and Entity Framework.
I have created the Entity Framework model and Domain Services in my DAL project.
Having clicked the 'Enable Client Code Generation' whilst creating the Domain Service everything works fine. The generated code is created in the client application as I can see the .g.cs file.
I decided to add a stored procedure to the EF model by adding a function and creating a complex type.
Then I proceeded to add this code to my Domain Service (MyDomainService.cs) class as shown below:
public IQueryable GetJournalItemList()
{
return this.ObjectContext.ExecuteFunction("GetJournalList", null).AsQueryable();
}
The problem I'm facing now is that when I build my solution I cannot see the new code in the client generated code class (.g.cs) in Silverlight client application. The proxy has no reference to the new GetJournalItemList which references the newly added stored procedure.
So here's my question: how to force a refresh of the client generated code so changes to the Domain Service class can be shown?
Thank You
You must return a strongly typed result. i.e.
public IQueryable<JournalItemList> GetJournalItemList()
{
return this.ObjectContext
.ExecuteFunction("GetJournalList", null).AsQueryable();
}
In addition, if this has not already been done, JournalItemList must have a key defined. You can do this using a Metadatatype attribute through a custom partial class. When you generate the Domain Service, a .metadata.cs file would have been created. There should be examples you can use.
[MetadataType(JournalItemList.Metadata)]
public partial class JournalItemList
{
public class Metadata
{
// Assuming that JournalItemList.JournalItemId exists
[Key]
public int JournalItemId { get; set; }
}
}

webapi aspnet 4 Architecture

I've project using Entity Framework 5 Code First, WebApi, ASPNET MVC 4, Repository and Unit of Work pattern, etc.
My architecture is as follows:
One project for the POCOS
One project with the context, Repository, Unit Of Work, etc
One project with the contracts (IRepository, IUnitOfWork, etc)
One WebApi project which holds ApiControllers for each entity of the model (GET, POST, PUT, DELETE).
Now, if I don't want to use SPA (as I don't have time right now to learn it) and I want to do something quick, What should I do? a new ASPNET MVC 4 project with Controllers inheriting from Controller rather than ApiController, and those controllers consuming the WebApi controllers?
Like this?
public ActionResult Index()
{
return View(WebApiProj.Uow.Houses.GetAll());
}
That doesn't seems to be quite good as it should be creating a Get pointing to the WebApi controller in the other project.
I'm thinking about this architecture, because mobile clients, web clients and any other clients would be calling the same services which sounds good.
Any advices on this architecture? Pros or cons?
I am not sure if what you show is possible? WebApiProj.Uow.Houses.GetAll() Is treating Houses as if it was a class with a static GetAll function on it. Houses is an instance class that needs to be instantiated per request and may/should have constructor injection concerns to handle too... GetAll would normally be an instance method.
Given you are in a situation where you are going to have multiple code clients i.e. the WebApi controllers and the MVC controllers you should consider adding a Service Layer to your project. http://martinfowler.com/eaaCatalog/serviceLayer.html.
Your Service Layer will probably take the form of a single class (if this is a small ish project but split it up if needed), it will have the Repositories and the Infrastructure code injected. You should end up with a series of CRUD and UseCase sounding method names that contain the orchestration logic between repositories, factories and unit of work classes.
public interface IMyServiceLayerClass
{
IEnumerable<House> GetAllHouses();
House SaveHouse(House house);
IEnumerable<Windows> GetAllHouseWindows(int houseId);
//etc
}
public class MyServiceLayerClass : IMyServiceLayerClass
{
private readonly IRepository<House> _houseRepository;
private readonly IUnitOfWork _unitOfWork;
private readonly IRepositoryTypeB _repositoryTypeB;
Public MyServiceLayerClass(IUnitOfWork unitofwork, IRepository<House> houseRepository, IRepositoryTypeB repositoryTypeB)
{
//Populate the private readonly's
}
public IEnumerable<House> GetAllHouses()
{
return _houseRepository.GetAll();
}
Your two types of controller can then accept the Service class and have very thin logic just to forward on to the service layer.
public class HomeController : Controller
{
private readonly IMyServiceLayerClass _myServiceLayerClass;
public HomeController(IMyServiceLayerClass myServiceLayerClass)
{
_myServiceLayerClass= myServiceLayerClass;
}
public ViewResult Index()
{
return View(_myServiceLayerClass.GetAllHouses());
}
Same for the Api:
public class HouseController : ApiController
{
private readonly IMyServiceLayerClass _myServiceLayerClass;
public HouseController (IMyServiceLayerClass myServiceLayerClass)
{
_myServiceLayerClass= myServiceLayerClass;
}
public IEnumerable<House> Get()
{
return _myServiceLayerClass.GetAllHouses();
}
This will allow you to reuse the same business logic and orchestration across the controllers abstract the logic away from your WebApi and Mvc applications.
This code could easily live in your project that defines the contracts as it is only dependent upon interfaces. Or you could add its interface into contracts too and then create another project class Domain or Service which can hold the implementation of the service class.
I would strongly suggest you leave you Controllers to do what they do best and let them handle the delegation of the UI specific elements and re-factor non UI specific logic into a reusable service layer. This would allow Unit tests for controllers to focus on testing for the correct action result and status codes etc and allow your domain logic to be tested independently.
Take a look at my answer for another architecture question on MVC. The key for your question is to have an application or domain layer that both the MVC Controller and Web API Controllers can use to access the business model (The M in MVC). You do not want to call the Web API directly from the MVC Controller as it has overhead for serialization and de-serialization that is not required here. Instead call the application/domain layer directly.

asp.net mvc without entity framework

I am learning asp.net mvc and went through a great tutorial that demonstrated it. The tutorial also used Entity Framework.
We have our own data access class which I have to use.
I am a little bit confused as to what I need to do to bridge the gap between our class and MVC framework.
For example, in the tutorial, inside of MovieController.cs file, there is a Edit method, that looks like this:
[HttpPost]
public ActionResult Edit(Movie movie)
{
if (ModelState.IsValid)
{
db.Entry(movie).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(movie);
}
If I don't use the Entity framework, what would it look like? Will I still need to use ModelState.IsValid and save the state like it's done
db.Entry(movie).State = EntityState.Modified;
Please advise. A clearly written example of using asp.net mvc without the use of Entity framework would be great.
What I need to know is what role does state play here and whether it is mandatory to use or is it just a part of how the Entity framework operates.
I would re-write this as:
[HttpPost]
public ActionResult Edit(Movie movie)
{
myDBObject.SaveChanges();
return RedirectToAction("Index");
}
Where myDBObject is my custom database access object.
The examples you see out there where controllers use directly some data access framework such as Entity Framework are bad examples. The whole internet is polluted with such stuff. I can hardly look at it without having my eyes hurt. I consider those as bad practices. Data access should be separated and abstracted in a repository. So for example:
public interface IMoviesRepository
{
Movie Get(int id);
void Save(Movie movie);
}
then you could have some implementation of this interface using plain ADO.NET, EF, NHibernate, a remote web service call, some custom ORM or really whatever:
public class MyCustomFrameworkMoviesRepository: IMoviesRepository
{
...
}
and the controller will take this repository interface as constructor argument:
public class MoviesController: Controller
{
private readonly IMoviesRepository _repository;
public MoviesController(IMoviesRepository repository)
{
_repository = repository;
}
public ActionResult Index(int id)
{
var movie = _repository.Get(id);
return View(movie);
}
[HttpPost]
public ActionResult Index(Movie movie)
{
if (!ModelState.IsValid)
{
return View(movie);
}
_repository.Save(movie);
return RedirectToAction("Success");
}
}
and the last part is to configure your dependency injection framework to pass the correct implementation of the repository into the controller. Now as you can see the way the data is fetched is completely decoupled from the controller logic. It is the way it should be. Always try to avoid the strong coupling between the different layers of your application.
And to answer your question about the State property : this is something completely specific to EF, seeing something like this in a controller is a really pity.
And to bring this even further and improve it you would introduce view models. View models are classes which are specifically designed to meet the requirements of a given view. So for example Movie is a domain model. Domain models should never be directly passed to views. Controller actions should never take domain models as action arguments. You should define view models which will contain only what is required by the given view and then perform the mapping between the view models and the domain models. Frameworks such as AutoMapper make this very simple.
hmm.
MVC and entity framework really have nothing to do with each other; they just work well together.
the if (ModelState.IsValid) validates your view model. If you are not using view objects with validators, it's a little pointless; if you are, then it's quite valuable.
inside the if (ModelState.IsValid) brackets, you would take the post data from your web page (usually a view model) and apply it to the object that will persist it to the database. EF is often used because once it's set up, it's fairly easy to maintain, and a lot less code to write.
db.Entry(movie).State = EntityState.Modified;
db.SaveChanges();
are both EF-related. These would need to be replaced by your repository class methods and objects.
return RedirectToAction("Index");
is MVC. Upon successful persistence to your data store, return the control to the index page.
return View(movie);
is used to redirect back to the original view, because something failed validation.
You would still check ModelState.IsValid, but otherwise your code would look like what you have.
This assumes that your model has DataAnnotations attributes on it, though, which is what ModelState.IsValid is using to check. Those attributes can be used on any C# class' properties - not just Entity Framework.
You might end up creating specific view models for this purpose.
You need to make some connection between the Movie object (passed in on the http POST) and your database methods (myDBObject).
Maybe you want to say myDBObject.SaveChanges(movie) and assuming your db code knows how to handle the object Movie then you'll be fine.