Use repository in referenced dll using entity framework - entity-framework

I have created a DLL that contains lots of authentication and user management that I'm trying to use in a separate project (MVC 3 Website).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using TestProj.Authentication;
namespace TestSite.MVC.Areas.Admin.Controllers
{
public class TestController : Controller
{
AuthenticationRepository authrep = new AuthenticationRepository();
public ActionResult Index()
{
authrep.DeleteUser(1);
return View();
}
}
}
Now this obviously does'nt work, which is understandable.
Is it dependency injection I need here?
And in that case, how would the basic code look for that?
Do I need to add something in the constructor for the referenced DLL?

Try structuring your controller like this:
public class TestController : Controller
{
IAuthenticationRepository AuthenticationRepository { get;set; }
public void TestController (IuthenticationRepository authenticationRepository)
{
this.AuthenticationRepository = authenticationRepository;
}
public ActionResult Index()
{
this.AuthenticationRepository.DeleteUser(1);
return View();
}
}
Create an interface for your repository. You could then use a DI framework (like Ninject for MVC 3) to inject instances of AuthenticationRepository into usages of IAuthenticationRepository.
https://github.com/ninject/ninject/wiki

Related

Pass DbContext to class library

I am developing an API to get data from the database using the entity framework. I have a class library to handle my generic tasks, including Repository, UnitOfWork etc. My UnitOfWork class is as follows.
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using AppPermission.Data.DataContext;
using AppPermission.Data.Models;
using AppPermission.Data.Repositories;
namespace AppPermission.Common.UnitOfWork
{
public class UnitOfWork : IUnitOfWork
{
private readonly DbContext dbContext;
public UnitOfWork(DbContext context)
{
dbContext = context;
}
public int SaveChanges()
{
return dbContext.SaveChanges();
}
public async Task<bool> SaveChangesAsync()
{
return await dbContext.SaveChangesAsync() > 0;
}
public void Dispose()
{
dbContext.Dispose();
GC.SuppressFinalize(this);
}
}
}
My API's ConfigureServices is as below
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<AppDbContext>();
services.AddSession();
services.AddControllersWithViews();
services.AddRazorPages();
services.AddScoped<IUnitOfWork, UnitOfWork>();
}
I want to pass AppDbContext registered in the API startup to UnitOfWork in the class library. There were a couple of solutions in StackOverflow using(services.BuildServiceProvider), but the connection is disposed of after the first API call (GetAll). Is there any way of doing it? If I place my UnitOfWork in the API project itself and changing the constructor in UnitOfWork to accept AppDbContext, it works fine?
It's a good idea to use Generic UnitOfWork :
public class UnitOfWork<TContext> : IUnitOfWork where TContext : DbContext
class constructor :
public UnitOfWork(TContext context, ILogger<UnitOfWork<TContext>> logger){}
Then add it to IServiceCollection like this :
services.AddScoped<IUnitOfWork, UnitOfWork<MonitoringDbContext>>();

Disposal and injecting DbContexts with .NET Core

I know that one way to use a context is via the using statement.
I use it like so within my controllers
[ApiController]
public class MyController : ControllerBase
{
[HttpPost]
public ActionResult PostActionHere(ActionRequestClass request)
{
using (var context = new MyEntityFrameworkContext())
{
....
// use context here
context.SaveChanges()
....
}
}
}
I would like to start injecting it into my controller. Mainly because I think it is easier to read and is more uniform with .NET Core dependency injection.
[ApiController]
public class MyController : ControllerBase
{
private MyEntityFrameworkContext _myDb;
public MyController(MyEntityFrameworkContext myDb)
{
_myDb = myDb;
}
[HttpPost]
public ActionResult PostActionHere(ActionRequestClass request)
{
....
// use context here
_myDb.SaveChanges()
....
}
}
Within my startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MyEntityFrameworkContext >(options =>
options.UseSqlServer(Configuration.GetConnectionString("MyEntityFrameworkDatabase")));
}
What I am worried about is that injecting it I lose the disposal properties that come with the using statement. Is that true? Feel free to suggest alternate approaches.
injecting it I lose the disposal properties that come with the using statement. Is that true?
No:
The AddDbContext extension method registers DbContext types with a
scoped lifetime by default.
Configuring a DbContext
And when the scope (here the HttpRequest) ends, the Scoped Lifetime object will be Disposed.

Entity Framework Core DbContext and Dependency Injection

I'm building a service application using Web API, .Net Core and EntityFramework Core.
For configuring options in my DbContext I'm using these lines in "ConfigureServices" method in Startup.cs
var connection = #"Server=ISSQLDEV;Database=EventManagement;Trusted_Connection=True;";
services.AddDbContext<EMContext>(options => options.UseSqlServer(connection));
I know that if I add the context as a constructor parameter in the controller .Net will inject the context in the constructor.
But this is not the behavior I want. I don't want my web api to know anything about the dbcontext. I have a DataAccess Project with a repository class that handles all CRUD operations.
This means that I just want to say Repository.AddEvent(evt) in my controller and then repository knows how to handle that.
On the other hand, repository uses a simple dependency resolver to get the right "IDataAdapter" implementation. One of those implementations is SQLDataAdapter. This is the point I need my context.
How can I pass my context all the way to this point?
You can solve this by adding your dbcontext via constructor injection to your classes from your data access layer.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(o => o.UseSqlServer(myConnStr));
services.AddScoped<Repository>(); // 'scoped' in ASP.NET means "per HTTP request"
}
}
public class MvcController
{
private Repository repo;
public MvcController(Repository repo)
{
this.repo = repo;
}
[HttpPost]
public void SomeEndpoint()
{
this.repo.AddFoo(new Foo());
}
}
public class Repository
{
private DbContext db;
public Repository(ApplicationDbContext db)
{
this.db = db;
}
public void AddFoo(Foo obj)
{
this.db.Set<Foo>().Add(obj);
this.db.SaveChanges();
}
}
If you want to further customize how your DbContext is injected into your DI container, I suggest you look at what .AddDbContext is actually doing. See https://github.com/aspnet/EntityFramework/blob/1.0.0/src/Microsoft.EntityFrameworkCore/EntityFrameworkServiceCollectionExtensions.cs#L142-L158

Token Based Authentication using ASP.NET Web API 2, Owin, AspNet.Identity.MongoDB and mongocsharpdriver

+after successfully implementing Token Based Authentication using ASP.NET Web API 2, Owin, and Identity, i wished to change my implementation to use MongoDB instead of MSSQL with Entity Framework, with the help of this application here....truth be said, i dont fully understand how this should be done, but at least i know what i want my application to behave. i want to follow this IMPLEMENTATION HERE, using AspNet.Identity.MongoDB and mongocsharpdriver...and so far, here,s what I've done:
Account Controller
using Microsoft.AspNet.Identity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using withMongoDB.HelperClasses.Services;
using withMongoDB.Models.Account;
namespace withMongoDB.Controllers
{
[RoutePrefix("api/Account")]
public class AccountsController : ApiController
{
AccountsService _accountsService = new AccountsService();
// POST api/Account/Register
[AllowAnonymous]
[Route("Register")]
public async Task<IHttpActionResult> Register(UserModel userModel)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
await _accountsService.Register(userModel);
return Ok();
}
private IHttpActionResult GetErrorResult(IdentityResult result)
{
if (result == null)
{
return InternalServerError();
}
if (!result.Succeeded)
{
if (result.Errors != null)
{
foreach (string error in result.Errors)
{
ModelState.AddModelError("", error);
}
}
if (ModelState.IsValid)
{
// No ModelState errors are available to send, so just return an empty BadRequest.
return BadRequest();
}
return BadRequest(ModelState);
}
return null;
}
}
}
then the register method from the controller should be taken by the accounts Service
using AspNet.Identity.MongoDB;
using Microsoft.AspNet.Identity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using withMongoDB.Models.Account;
namespace withMongoDB.HelperClasses.Services
{
public class AccountsService
{
private readonly MongoAccountsConnectionHelper<UserProfile> _accounts;
public AccountsService()
{
_accounts = new MongoAccountsConnectionHelper<UserProfile>();
}
public async Task<IdentityResult> Register(UserModel userModel)
{
var userprofile = new UserProfile
{
UserName = userModel.UserName
};
var result = await _accounts.CreateAsync(userprofile, userModel.Password);
return result;
}
}
}
and finally the MongoAccountsConnectionHelper takes the result of the accounts service class to mongo database....
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace withMongoDB.HelperClasses
{
using AspNet.Identity.MongoDB;
//using Entities;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Conventions;
using MongoDB.Driver;
using System.Configuration;
using withMongoDB.Models.Account;
public class MongoAccountsConnectionHelper
{
private readonly MongoCollection<UserProfile> userProfileCollection;
public MongoDatabase Database { get; private set; }
public MongoAccountsConnectionHelper()
{
var pack = new ConventionPack()
{
new CamelCaseElementNameConvention(),
new EnumRepresentationConvention(BsonType.String)
};
ConventionRegistry.Register("CamelCaseConvensions", pack, t => true);
var mongoUrlBuilder = new MongoConnectionStringBuilder(ConfigurationManager.ConnectionStrings["MongoDB"].ConnectionString);
Database = new MongoClient().GetServer().GetDatabase(mongoUrlBuilder.DatabaseName);
userProfileCollection = Database.GetCollection<UserProfile>("users");
}
public MongoCollection<UserProfile> Users
{
get { return userProfileCollection; }
}
}
}
any help, tips, ideas, or opinions will be highly appreciated....{should i consider alternatives like MembershipReboot and IdentityReboot by brockallen?}
To do it smoothly, you need first to remove the dependency on "Microsoft.AspNet.Identity.EntityFramework", by providing your own user class/table (which should implements IUser as a minimum), and Also you need to implement the UserManager class (which should imeplements UserManager, and finally you need to implement the UserStore class (which should implement IUserStore as minimum) where T is the Id type in the User Table.
Once you done the above, then it is the UserStore where you can change to use MongoDB.
Hope that helps.

MVC2 & Ninject2 - Controllers not resolving dependency

I foolishly decided to try something new on a Friday job!
So I have used NuGet to add Ninject.Web.Mvc 2.2.x.x to my .Net MVC2 project.
I've altered my Global.asax.cs
using System.Web.Mvc;
using System.Web.Routing;
using IntegraRecipients;
using Mailer;
using Ninject;
using Ninject.Web.Mvc;
using Ninject.Modules;
namespace WebMailer
{
public class MvcApplication : NinjectHttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("favicon.ico");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Mail", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
protected override void OnApplicationStarted()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
}
protected override IKernel CreateKernel()
{
return new StandardKernel(new INinjectModule[] { new MailModule()});
}
internal class MailModule : NinjectModule
{
public override void Load()
{
Bind<IMailing>().To<Mailing>();
Bind<IMailingContext>().To<MailingContext>();
Bind<IRecipientContext>().To<RecipientContext>();
}
}
}
}
and I've created a controller like so...
using System.Linq;
using System.Web.Mvc;
using WebMailer.Models;
namespace WebMailer.Controllers
{
[ValidateInput(false)]
public class MailController : Controller
{
private readonly IMailingContext _mailContext;
private readonly IRecipientContext _integraContext;
public MailController(IMailingContext mail,IRecipientContext integra)
{
_mailContext = mail;
_integraContext = integra;
}
public ActionResult Index()
{
return View(_mailContext.GetAllMailings().Select(mailing => new MailingViewModel(mailing)).ToList());
}
}
}
But the controller is still insisting that
The type or namespace name 'IRecipientContext' could not be found (are you missing a using directive or an assembly reference?)
and
The type or namespace name 'IMailingContext' could not be found (are you missing a using directive or an assembly reference?)
My google-fu has failed me and I really hope this is just a silly typo/missing line thing
Thanks in advance
P
Ninject does not change the way assemblies are compiled! It deos not magically add references to other assemblies or add using directives. If you are using interfaces from other assemblies you have to add a using directive and a reference to this assembly.
All Ninject is about is to wire up your application at runtime.
I am have what appears to be a similar problem.
I have a simple WPF Window project with the compiled Ninject.dll linked in. However, the following is giving me errors...
using Ninject;
namespace CatalogueManager
{
public class ServiceLocator
{
public IMainWindowViewModel GetMainWindowViewModel()
{
return Kernel.Get<IMainWindowViewModel>();
}
static IKernel Kernel;
static ServiceLocator()
{
Kernel = new StandardKernel(new NinjectConfiguration());
}
}
}
In particular, "Ninject" namespace and IKernel are prompting the compile time message "type or name space 'X' not found..."