How can I use one DbContext with multiple application?
I have a WCF application (Net TCP binding) interface and implementation works fine with the DbContext. There is a need for API from the same application and I don't want to enable Http Binding on the WCF because of configuration and I have so many contracts. so I decided to import the service into asp.net core 2 via DI it works fine but works connect to Db via DbContext always returning null.
DB Context:
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options){}
public AppDbContext()
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(#"Server=.\;Database=Database;Trusted_Connection=True;MultipleActiveResultSets=true");
}
}
}
Service implementation
public partial class GeneralService : IGeneralService, IDisposable
{
protected readonly AppDbContext Db = new AppDbContext();
public void Dispose()
{
Db.Dispose();
}
}
Asp.net core Start Up
public void ConfigureServices(IServiceCollection services)
{
const string connection = #"Server=.\;Database=Database;Trusted_Connection=True;MultipleActiveResultSets=true";
services.AddDbContext<AppDbContext>(options => options.UseSqlServer(connection));
services.AddSingleton<IGeneralService,GeneralService>();
services.AddMvc()
.AddJsonOptions(options => options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver());
}
what am I doing wrong, what can I do I really don't want to use Proxy
connect to Db via DbContext always returning null.
I think that might be down to the fact that you're creating the DB context directly in the service class. You can/should inject your DbContext into your service instead. Something like:
public partial class GeneralService : IGeneralService, IDisposable
{
protected readonly AppDbContext Db;
public GeneralService(AppDbContext db)
{
Db = db;
}
// ... etc...
}
Further, since you're providing a connection string to the db in your Startup.cs you don't need the OnConfiguring method in your db context.
Finally, services shouldn't be singletons if they're using EF. See this answer which recommends the Request scope.
Related
In order to connect to a database in the ASP.NET Core Application we create a DbContext
namespace MyProject.Models
{
public class MyProjectContext : DbContext
{
public MyProjectContext (DbContextOptions<MyProjectContext> options)
: base(options){ }
public DbSet<MyProject.Models.Record> Record { get; set; }
}
}
In Startup.cs we do
public void ConfigureServices(IServiceCollection services) {
// Adds services required for using options.
//...
// Add framework services.
services.AddMvc();
services.AddDbContext<MyProjectContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("MyProjectContext")));
}
And Finally in the Controller we have
namespace MyProject.Controllers
{
public class RecordsController : Controller
{
private readonly MyProjectContext _context;
public RecordsController(MyProjectContext context) {
_context = context;
}
// GET: Records
public async Task<IActionResult> Index() {
return View(await _context.Record.ToListAsync());
}
OK, all that is from the VS scaffolding...
=============================================================
I have now to do with AzureTables, so I did a test controller that does
Startup.cs
public void ConfigureServices(IServiceCollection services) {
// Adds services required for using options.
...
// Register the IConfiguration instance which "ConnectionStrings" binds against.
services.Configure<AppSecrets>(Configuration);
HelloWorldController.cs
namespace MyProject.Controllers
{
public class HelloWorldController : Controller
{
CloudTableClient cloudTableClient = null;
public HelloWorldController(IOptions<AppSecrets> optionsAccessor) {
string azureConnectionString = optionsAccessor.Value.MyProjectTablesConnectionString;
CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse(azureConnectionString);
cloudTableClient = cloudStorageAccount.CreateCloudTableClient();
}
public async Task<string> ReadTables() {
CloudTable table = cloudTableClient.GetTableReference("themes");
StringBuilder response = new StringBuilder("Here is your test Table:");
var query = new TableQuery<DescriptionEntity>() {
SelectColumns = new List<string> { "RowKey", "Description" }
};
var items = await table.ExecuteQuerySegmentedAsync<DescriptionEntity>(query, null);
foreach (DescriptionEntity item in items) {
response.AppendLine($"Key: {item.RowKey}; Value: {item.Description}");
}
return response.ToString();
}
Question
How can I integrate the Azure Tables in the same way like the SQL Context does? I mean, having the same 3 steps for the Azure Tables:
Create the Azure Tables Context,
Configure Services (via ConfigureServices(IServiceCollection) in Startup.cs),
Pass the "IAzureTable context" to the Controller's constructor ?.
I am complete newbie, a code example of the steps would be greatly appreciated.
How, by eg, create the Azure DBContext (if there is a need for such one)?
According to this article(EF's roadmap), the azure table storage as EF's dbcontext database doesn't support now. It is in the high priority features and will be released in the future.
So we couldn't use the table storage as EF's dbcontext in the .net core now.
You could see the "High priority features" contains the azure table provider as below.
High priority features
Providers
Azure Table Storage
Redis
Other non-relational databases
If you want to use azure table storage in the ,net core, I suggest you could use azure storage SDK(installed from the Nuget package) and write youe own logic to CRUD the data.
I have the following unit of work pattern set up for an MVC 5 application using Entity Framework. The unit of work has all the repos defined as follows so that they are all using the same dbcontext and it has one save method to co-ordinate the transaction using the same context:
public class UnitOfWork : IUnitOfWork
{
private readonly ApplicationDbContext _context;
public IProductRepository ProductRepository { get; private set; }
public ICustomerRepository CustomerRepository { get; private set; }
// Other reposistories
public UnitOfWork(ApplicationDbContext context)
{
_context = context;
ProductRepository = new ProductRepository(_context);
CustomerRepository = new CustomerRepository(_context);
// Other reposistories
}
public void Complete()
{
_context.SaveChanges();
}
}
This is an example of my repo. The reason for using repos is for code re-use so that I'm not duplicating queries inside different controllers.
public class ProductRepository : IProductRepository
{
private readonly ApplicationDbContext _context;
public ProductRepository(ApplicationDbContext context)
{
_context = context;
}
public Product GetProduct(int productId)
{
return _context.Ticket.SingleOrDefault(p => p.Id == productId);
}
public void Add(Product product)
{
_context.Product.Add(product);
}
// Other methods
}
I inject the unit of work class in my controller as follows using Ninject:
public class ProductsController : Controller
{
private readonly IUnitOfWork _unitOfWork;
private readonly IFileUploadService _FileUploadService;
public ProductsController(IUnitOfWork unitOfWork,
IFileUploadService fileUploadService)
{
_unitOfWork = unitOfWork;
_FileUploadService = fileUploadService;
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CreateEditProductViewModel viewModel)
{
var product = new Product
{
// Do stuff
};
_unitOfWork.ProductRepository.Add(product);
// Call file upload service
_fileUploadService.Upload();
_unitOfWork.Complete();
}
}
This unit of work set up works fine if all I'm using are repos that are defined in the unit of work class. But now I want to use a service class to process some additional application logic and then the unit of work is committed in the controller action. If I define the class as follows it will be using a different instance of the context, In which case how would you co-ordinate a transaction where the service layers is ending up with a different context?
public class FileUploadService : IFileUploadService
{
private readonly IUnitOfWork _unitOfWork;
public FileUploadService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public uploadResult Upload()
{
// Some stuff
var uploadedFile = new UploadedFile
{
//some stuff
};
_unitOfWork.UploadedFileRepository.Add(uploadedFile);
}
}
I've done quite a bit of research online and I'm unable to find any resource that provides a practical example to solve this problem. I've read quite a bit of stuff on ditching unit of work and repos and simply using entity frameworks dbset. However as explained above the purpose of using
repos is to consolidate queries. My questions is how do I co-ordinate the unit of work with a service class.
I would like the service to use the same context so that it can access the repositories it needs to work with, and let the controller (client code) commit the operation when it see fits.
* UPDATE *
In my DI Container I resolve all interfaces using the following snippet:
private static IKernel CreateKernel()
{
RegisterServices(kernel);
kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
// default binding for everything except unit of work
kernel.Bind(x => x.FromAssembliesMatching("*")
.SelectAllClasses()
.Excluding<UnitOfWork>()
.BindDefaultInterface());
return kernel;
}
Would adding the line kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope(); ensure that no more than one ApplicationDbContext is created, even if the request ends up hitting multiple controllers or service layers that all require an IUnitOfWork (ApplicationDbContext)?
If you are using MVC, then your unit of work is your web request. If I were you I'd ditch the UOW implementation and just make sure you dbcontext is instantiated in the Application_BeginRequest. Then I'd stuff it into the HttpContext for safe keeping. On Application_EndRequest, I dispose of the DbContext.
I would move the save to your repository.
I'd create a [Transaction] attribute that would maintain a TransactionScope something like this:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class TransactionAttribute : ActionFilterAttribute
{
private TransactionScope Transaction { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
Transaction = new TransactionScope( TransactionScopeOption.Required);
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Exception == null)
{
Transaction.Complete();
return;
}
Transaction.Dispose();
}
}
You can then just tag your controller methods with [Transaction].
I'm just spitballing here, but I do something similar with NHibernate instead of EF and it works out nicely for me.
The InRequestScope() will create a new instance of the bound type on every new web request, and at the end of that web request, it will Dispose that instance if it is disposable.
I am not sure how are you passing the ApplicationDbContext into your UnitOfWork. I am assuming that you use Ninject for this injection too. Just make sure that you bind your ApplicationDbContext using the InRequestScope()Bind.To().InRequestScope();.
This way, your ApplicationDbContext instance will be created once per request and disposed at the end.
Also, the use of InRequestScope is for types that are disposable, so you can also release resoruces in the Dispose method of your UnitOfWork method too.
I'm trying to use SimpleInjector 2.7.3 (IoC container) within an Asp.Net MVC + Web API application.
I've had a couple of problems trying to set it up for both MVC and Web API on the same project until I found this link:
http://methoddev.com/blg/let-s-talk-software/310/simple-injector-in-asp-net-mvc-webapi
After following the link's example, here's what I got:
One of my Web API controllers:
public class UserController : BaseApiController
{
private readonly IUserService service;
public UserController(IUserService userService)
{
// I should point that IUserService is being injected correctly here
this.service = userService;
}
public IHttpActionResult Post(CreateUserRequest request)
{
return Ok();
}
}
The problem happens when I try to execute the Post operation. The CreateUserRequest class itself has a dependency.
public class CreateUserRequest : IValidatableObject
{
private readonly IValidator<CreateUserRequest> validator;
public CreateUserRequest(IValidator<CreateUserRequest> _validator)
{
// _validator is not being injected, I'm getting null here
validator = _validator;
}
public string SomeProperty { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
// My validation logic here must call the validator injected
// when the object was created.
return null;
}
}
I should point that IValidator is an interface from the FluentValidator package.
Anyway, when CreateUserRequest is instantiated the validator is null, which means it's not being injected.
When I'm creating the SimpleInjector Container I can see the type correctly registered, so I don't think that is a problem.
I did the following change to CreateUserRequest class:
public class CreateUserRequest : IValidatableObject
{
private readonly CreateUserRequestValidator validator;
// Changed here to the concrete class
public CreateUserRequest(CreateUserRequestValidator _validator)
{
validator = _validator;
}
// ...
}
So, I changed the interface to a concrete class and I'm still receiving a null there.
The only thing I can imagine is that this is somehow related to the custom dependency resolver suggested by the aforementioned link. I needed to use that in order to have the same dependency resolution logic for both MVC and Web API. Here's the code:
public class SimpleInjectorDependencyResolver : System.Web.Mvc.IDependencyResolver,
System.Web.Http.Dependencies.IDependencyResolver,
System.Web.Http.Dependencies.IDependencyScope
{
public SimpleInjectorDependencyResolver(Container container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.Container = container;
}
public Container Container { get; private set; }
public object GetService(Type serviceType)
{
if (!serviceType.IsAbstract && typeof(IController).IsAssignableFrom(serviceType))
{
return this.Container.GetInstance(serviceType);
}
return ((IServiceProvider)this.Container).GetService(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return this.Container.GetAllInstances(serviceType);
}
IDependencyScope System.Web.Http.Dependencies.IDependencyResolver.BeginScope()
{
return this;
}
object IDependencyScope.GetService(Type serviceType)
{
return ((IServiceProvider)this.Container).GetService(serviceType);
}
IEnumerable<object> IDependencyScope.GetServices(Type serviceType)
{
return this.Container.GetAllInstances(serviceType);
}
void IDisposable.Dispose()
{
}
}
I don't really know a lot of the plumbing behind MVC and Web API (specially the custom dependency resolver feature), so, I'm really stuck on this one.
I appreciate any help figuring that out. Thanks.
--UPDATE--
In addition to the answer given by Steven, I would like to leave a link to whoever falls into the same problem. It's a great resource:
https://brettedotnet.wordpress.com/2014/07/16/web-api-and-interface-parameters/
The reason why your view model object isn't auto-wired by Simple Injector is because both MVC and Web API don't build view model objects using the IDependencyResolver. So creating a special dependency resolver won't work. If you want to let your view models to be auto-wired, you will have to override the default model binder in MVC and Web API.
But I urge you not to do this. In my opinion, a model binder should just do data conversion and a view model should be a plain DTO. Although it is fine to mark view models with validation attributes, letting them have behavior using services that might even trigger any database communication is a big no-no in my book. This can complicate development tremendously.
This however means that this validator should be injected elsewhere. Without making any changes to your architecture, this basically means you will have to inject that validator in the controller instead:
public class UserController : BaseApiController
{
private readonly IUserService service;
private readonly IValidator<CreateUserRequest> validator;
public UserController(IUserService userService,
IValidator<CreateUserRequest> validator)
{
this.service = userService;
this.validator = validator;
}
}
Obviously this can easily complicate your controllers with extra dependencies and logic, but that's because validation is a cross-cutting concern that you would like to probably keep out of your controllers.
If you try to address this, you will eventually end up with a message passing architecture such as described here.
As I understand a connection string is attached to one class only. But what if I have many Model classes? Can I use one connection string for multiple classes?
This is a simple version of my UserModel.cs file:
public class UserModel
{
public int Id { get; set; }
public string Email { get; set; }
}
public class UserTable : DbContext
{
public UserModel GetByEmail(string Email)
{
return this.Database.SqlQuery<UserModel>("SELECT * FROM Users WHERE Email=#Email", new SqlParameter("Email", Email)).SingleOrDefault();
}
}
And this is the connection string:
<connectionStrings>
<add name="UserModel"
connectionString="Server=.\SQLEXPRESS;Database=MyDatabase;User Id=MyUser;Password=MyPassword;"
providerName="System.Data.SqlClient" />
</connectionStrings>
Now lets say I want to add a new Model class named DataTable also derived from DbContext as user table is. Do I need a connection string named the same or can I use the already defined one? What is the conventional way of dealing with multiple Model classes and connection strings?
The DbContext class uses the ConnectionString to make the connection to the database.
You normally have multiple model classes exposed by a DbContext.
It is possible to have multiple DbContext objects that use the same connection string value to connect to the database. In this way, you can separate portions of your model into separate contexts if desired (for example, if you are creating separate assemblies that access different tables but provide similar services to the application).
One caveat to note with EF up to at least 5.0, you cannot use the code-first migrations with multiple DbContexts, one will overwrite the other's changes. The solution to this is to create an aggregated DbContext that is only used for the Migrations process.
I've done this in an app that I built. I used the Unity IoC container, and the built a Plugin Interface that allowed me to pass my ConnectionStringName into my separated DbContexts. An example of the plugin in one of the assemblies was:
public class Bootstrapper : IBootstrapper
{
public void Bootstrap(IUnityContainer container, string connectionStringName)
{
container.RegisterType<ISQService, SQService>();
container.RegisterType<ISQEntities, SQEntities>(
new HierarchicalLifetimeManager(), new InjectionConstructor(connectionStringName));
container.RegisterType<IController, SQController>("SQ");
}
}
My global.asax referenced the bootstrapper class below:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
ModelBinders.Binders[typeof(DataTable)] = new DataTableModelBinder();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
Bootstrapper.Initialise();
}
protected void Application_End()
{
Bootstrapper.Dispose();
}
Bootstrapper
public static class Bootstrapper
{
private static IUnityContainer container;
public static void Initialise()
{
container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
public static void Dispose()
{
container.Dispose();
}
private static void RegisterPlugins(IUnityContainer theContainer, string wildcard, string connectionStringName)
{
var pluginBootStrappers = from Assembly assembly in wildcard.LoadAssemblies()
from type in assembly.GetExportedTypes()
where typeof(IBootstrapper).IsAssignableFrom(type)
select (IBootstrapper)Activator.CreateInstance(type);
pluginBootStrappers.ToList().ForEach(b => b.Bootstrap(theContainer, connectionStringName));
}
private static IUnityContainer BuildUnityContainer()
{
var theContainer = new UnityContainer();
const string ConnectionStringName = "MyDb";
RegisterPlugins(theContainer, "MyApp.Systems.*.dll", ConnectionStringName);
// Register Application Specific objects
theContainer.RegisterType<IMyEntities, MyEntities>(
new HierarchicalLifetimeManager(),
new InjectionConstructor(ConnectionStringName));
theContainer.RegisterType<IAimaService, AimaService>();
var factory = new UnityControllerFactory(theContainer);
ControllerBuilder.Current.SetControllerFactory(factory);
return theContainer;
}
}
The connection string defines the parameters needed to connect to the DB.
Maybe I think you are talking about or confusing the SQL Query with the connectionstring.
Yes one SQL Query can QUERY more than one table at any given time.
Maybe you could look into the "SQL Query Statement" on google for in depth information.
I have a small MVC application that connects to a single MYSQL database. I had it setup with Ninject to bind the connectionString during the application startup. The code looked like this:
Global.asax.cs:
protected void Application_Start()
{
...
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
}
NinjectControllerFactory.cs:
public class NinjectControllerFactory : DefaultControllerFactory
{
...
private class EriskServices : NinjectModule
{
public override void Load()
{
// Bind all the Repositories
Bind<IRisksRepository>().To<MySql_RisksRepository>()
.WithConstructorArgument("connectionString",
ConfigurationManager.ConnectionStrings["dbcMain"]
.ConnectionString);
}
}
}
Today my requirements have changed and I have to now support multiple databases. I would like to have each database connection string defined in the web.config file, like how it was before. The user selects which database they want to connect to during the application login.
What would be the easiest way to bind my repositories after the login? I'm assuming I would need to code the database binding in the login controller.
I am kind of a newbie to Ninject so any examples would be much appreciated!
As always, Thanks for the time and help!
.
I would probably Bind the repository to a Ninject.Activation.IProvider, and then create your own provider that pulls the connectionString from Session
Bind<IRisksRepository>().ToProvider<SessionConnectionProvider>();
then...
public class SessionConnectionProvider : Ninject.Activation.IProvider
{
#region IProvider Members
public object Create( Ninject.Activation.IContext context )
{
// use however you're accessing session here
var conStr = session.ConnectionString;
return new MySql_RisksRepository( conStr );
}
public Type Type
{
get { return typeof( IRisksRepository ); }
}
#endregion
}