.NET MVC 5 separate into different projects: avoid circular reference - c#

I have a solution that contains just one single project (MVC 5 with Identity and EF).
The db context is an ApplicationDbContext (a subclass of IdentityDbContext which is itself a subclass of EF DbContext).
I also have a custom validation attribute that needs to use the db context to do its thing:
public class RequiredIfRol : ValidationAttribute, IClientValidatable {
//...
protected override ValidationResult IsValid(object value, ValidationContext validationContext) {
// ...
string nomRol = "";
//instance and use the ApplicationDbContext
using (ApplicationDbContext db = new ApplicationDbContext()) {
var roldb = db.Roles.Find(rolId);
if (roldb == null) return ValidationResult.Success;
nomRol = db.Roles.Find(rolId).Name;
}
// more code here
}
}
This is working ok.
Now, after reading about it, I am trying to separate this MVC project into several projects:
a class library for the DAL (it will contain the EF models and the ApplicationDbContext),
another one for the business logic,
another one with common things
and then the MVC project.
I am noob on this, since I have always had everything inside the same MVC project, so I am confused:
I think the attribute should reside in the Common project, so that it can be referenced from the DAL (to decorate models) and also from the MVC (to decorate viewmodels).
Since the Common project will be referenced from all the other projects, I guess I can not reference any of those projects from the Common (circular reference?). and, as the ApplicationDbContext (which the attribute needs to use) will reside in the DAL project, I have a problem here...
I am pretty sure I am designing this badly, but cant find a correct way to do it.. Any help?
ADDED:
this is something I had tried:
1.- in the common library, defined an interface:
public interface IMyInterface {
System.Data.Entity.IDbSet<CustomRole> Roles { get; set; }
}
2.- in the applicationDbContext, modified its declaration so that it implements the interface:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, CustomRole, int, CustomUserLogin, CustomUserRole, CustomUserClaim>, IMyInterface {...}
3.- then in the attribute, try to get an implementation of the interface by adding an getter property:
private IMyInterface _dbcontext { get { return DependencyResolver.Current.GetService<IMyInterface>(); } }
and then in the IsValid() method:
var roldb = _dbcontext.Roles.Find(rolId);
if (roldb == null) return ValidationResult.Success;
nomRol = _dbcontext.Roles.Find(rolId).Name;
but this did not work...

One way around it would be to create an abstraction for your code using context - IRoleFinder and put in the common project alongside with your RequiredIfRol. Then implement it in business logic layer and inject it in the MVC project. This way you should be able to decouple you attribute from context.
ValidationAttribute.IsValid() has a ValidationContext parameter which you can use to resolve the dependency via ValidationContext.GetService method.
UPD
Per your request in comment:
For simplification, lets say I have only 2 projects (the class library with the attribute, and the MVC project with everything else).
In library you will have something like this:
interface IRoleFinder
{
CustomRole Find(int id);
}
public class RequiredIfRol : ValidationAttribute, IClientValidatable {
//...
protected override ValidationResult IsValid(object value, ValidationContext validationContext) {
// ...
var roleFinder = (IRoleFinder) validationContext.GetService(typeof(IRoleFinder));
}
}
In your MVC project:
public class RoleFinder : IRoleFinder
{
public CustomRole Find(int id)
{
// use context here
}
}
And in Startup (this is for ASP.NET Core, for MVC 5 you should find another way):
services.AddTransient<IRoleFinder, RoleFinder>()

Related

How to validate property on post

I have a asp .net mvc application. For all my other attributes, I've used data annotations to verify the attributes. But I would like to have a custom validation. I was reading online that a custom data annotation validation may be the approach to take.
Following this link here ASP.NET MVC: Custom Validation by DataAnnotation it looks like a great solution. The only issue I'm coming across is how do I access my DBContext if it's not within a controller.
What I have so far
This is the code I typicalled used in controllers to grab the current user and db context.
Controller code
private ApplicationDbContext _dbContext => HttpContext.GetOwinContext().Get<ApplicationDbContext>();
private ApplicationUserManager _userManager;
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
ViewModel
[HasNoRedemption]
public string code {get; set;}
HasNoRedemption.cs
public class HasNoRedemption : ValidationAttribute
{
public override bool IsValid(object value)
{
//check if user has ever claimed the code, return true is good
}
}
If I may get some assistance in making a custom validation such that I'll be able to check the db or a suggestion for a better approach.
1) I would not recommend using data annotation attributes to implement your business logic inside. Validation attributes are ought to contain pure functions. The intention behind the validation attributes is to narrow down the range of the input data that is considered to be correct. Not to implement business rules of your application
2) If you really wish to do what you want (for curiosity sake), check the following instructions: https://andrewlock.net/injecting-services-into-validationattributes-in-asp-net-core/
public class CustomValidationAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(
object value, ValidationContext validationContext)
{
// validationContext.GetService() ...
}
}

Entity Framework Generic Base Class

I have no choice in creating a data first Entity Framework implementation. I want to extend the generated class to include a generic base class that I can call all the basic functions on. (I know how to update the t4 templates)
Update (add if not currently in DB), GetAll, Select (based on parameters) and Delete functions. I have found a few things that I think may work but they do not have fully qualified namespaces and I can't figure out where the information is stored.
Creating base class for Entities in Entity Framework - is one such which is basically a duplicate of my question but the answers are not complete.
What would be an example of this base class WITH the fully qualified namespace?
You can still use Code First even though you have a database. You can generate your model. Depends what you need, please see 2 different ways to approach the problem.
Generic repository
public abstract class BaseRepository<TEntity> where TEntity : class
{
protected DbContext context;
protected BaseRepository(MyDbContext context)
{
this.context = context;
}
public List<TEntity> GetAll()
{
// Set<TEntity> provides you an access to entity DbSet
// Just like if you call context.Users or context.[AnyTableName]
return context.Set<TEntity>().ToList();
}
}
Next you want to implement entity-specific repositories:
public class UserRepository : BaseRepository<User>
{
public UserRepository(MyDbContext context) : base(context)
{
}
}
Simple usage example:
using (var context = new MyDbContext())
{
var userRepository = new UserRepository(context);
var users = userRepository.GetAll();
}
Just put your generic methods in context
public class MyContext : DbContext
{
public DbSet<User> Users { get; set; }
// ... more DbSets
public List<TEntity> GetAll<TEntity>() where TEntity : class
{
return Set<TEntity>().ToList();
}
// For entities that implement INamedEntity interface
// with property Name.
public TNamedEntity FindByName<TNamedEntity>(string name)
where TNamedEntity : INamedEntity, class
{
return Set<TNamedEntity>()
.FirstOrDefault(entity => entity.Name == name);
}
}
I use nuget package EntityFramework. DbContext and DbSet comes from System.Data.Entity namespace.
Hope it's enough for you to get started and implement all the methods that you need.

ASP.NET MVC 5 solution architecture improvement - multiple services with the same methods and code

I'm currently building an ASP.NET MVC 5 application using Unity and Entity Framework.
Here is my architecture (the solution contains multiple projects) :
Bootstrapper : project that contains the link between my interfaces and class for the repositories and the services
Data : mapping between my models and the database objects. This project contains the repositories as well.
Domain : this one contains the application constants + the interfaces of my repositories and services
Models : contains the models used in the application
Services : contains all the class Services
Web : the actual application with the views, controllers, view models, ...
Here is my issue: in multiple services I have the same methods (Get an item, check if it exists, ...) and these methods are exactly the same in every services except that they don't use the same repository and the same model.
Example :
public IQueryable<Car> Search(string search)
{
#region Sanitize parameters + Contracts
Contract.Requires<ArgumentException>(!string.IsNullOrEmpty(search), Resources.Resources.SearchRequired);
search = StringHelper.SafePlainText(search);
Contract.Assume(search.Length <= 100 && search.Length > 1);
#endregion
return _carRepository.Search(StringHelper.SafePlainText(search));
}
I want to "extract" these methods so I don't have to recreate the same code over and over.
First, I thought about create an abstract class that my service inherit from but I couldn't figure out how to pass the right repository to the mother class.
This is what I tried :
public abstract class Service<T>
{
public object Repository { get; set; }
protected Service(object repository)
{
Repository = repository;
}
public IQueryable<T> Search(string search)
{
#region Sanitize parameters + Contracts
Contract.Requires<ArgumentException>(!string.IsNullOrEmpty(search), Resources.Resources.SearchRequired);
search = StringHelper.SafePlainText(search);
Contract.Assume(search.Length <= 100 && search.Length > 1);
#endregion
return Repository.Search(StringHelper.SafePlainText(search));
}
}
But this, of course, doesn't work.
So I'm asking you guys if you have an idea to how I can manage to make this work, if this is possible at least.
Thank you in advance and excuse me for the poor language, I'm not an English native speaker.
Thibault.ce
First, you can inherits all your entity framework objects from a base class (optional) : http://fairwaytech.com/2013/09/using-a-common-base-class-across-entity-framework-database-first-entities/
Then, you can create a generic class "BaseRepository" which is based on the base class you created (or just "class"). This class will contains all generic methods. In this class, you can access the table corresponding to the base object using the entityframework method "Set()", which returns the DbSet of the typed pass in parameter.
After what you can inherit all your repositories from the "BaseRepository", and specify specific methods.
I made a simple example with 2 tables : https://dotnetfiddle.net/9hurx9
The best solution that I found is to create a generic class which depends of 2 types: The repository and the entity.
A BaseService< T1, T2 > which takes in parameter a "BaseRepository" and a "IEntity" and which will contain all the generic methods. This class must contain a property containing the instance of the repository. Thus, you can use the repository as shown in your example.
Then you can create specific Service classes, like a CarService which will inherit from BaseService< CarRepository, Car >.
A simple example, based on the example of my previous answer :
public class BaseService<TRepo, TEntity> where TRepo : BaseRepository<TEntity> where TEntity: IEntity
{
public TRepo Repository { get; set; }
public BaseService(TRepo repository)
{
this.Repository = repository;
}
public List<TEntity> GetAll()
{
return this.Repository.GetAll().ToList();
}
}
public class UserService : BaseService<UserRepository, User>
{
public UserService(UserRepository repository)
: base(repository)
{
}
public List<User> GetAllUserSortByName()
{
return this.Repository.GetAllUserSortByName();
}
}
You can use it like this :
YourEntities entities = new YourEntities();
UserRepository repo = new UserRepository(entities);
UserService service = new UserService(repo);
List<User> users = service.GetAllUserSortByName();
Let me know if my answer is not clear enough.
Edit :
Final example: https://dotnetfiddle.net/3s5BKZ
Thank you for you quick answer.
I managed to refactor my repositories and it's a really good point, thanks to your solution.
But at first my question was not about refactor my repositories but my services. I want to do the same process you did with the Entities.Set()... but with the call of my repositories.
Example:
I want to extract this method from my CarService :
public IQueryable<Car> GetAll()
{
return _carRepository.GetAll();
}
And put it in an abstract class Service. Something like :
public IQueryable<T> GetAll()
{
return Repository.GetAll();
}
But how to pass the right repository from the class CarService to the class Service ?
It's quiet hard to explain actually..
But thank you very much for the answer. It already helped me.

DbSet outside of DbContext class

My project has couple of Areas which each one of them has their own entities and I'm trying to keep everything isolate in that area... (lets call those areas = plugins)
DbContext
public class PortalDbContext : DbContext, IUnitOfWork
{
public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
{
return base.Set<TEntity>();
}
}
IUnitOfWork
public interface IUnitOfWork
{
int SaveChanges();
IDbSet<TEntity> Set<TEntity>() where TEntity : class;
}
Service.cs
public class PageService : IPage
{
public readonly IUnitOfWork _uow;
public readonly IDbSet<Pages> _page;
public PageService(IUnitOfWork uow)
{
_uow = uow;
_page = uow.Set<Pages>();
}
}
Finally When I try:
public void AddPage(PageModel m)
{
_page.Add(m);
}
I get this error:
The entity type Pages is not part of the model for the current context
this means uow.Set<Pages>(); doesn't worked properly.
is it possible to DbSet out of DbContext class is ASP.Net MVC code first?
Actually, this error message
The entity type Pages is not part of the model for the current context
means, that the type PageModel was not configured as an entity type for the PortalDbContext context instance. You should either follow conventions to build your model (see this page, "Type Discovery" paragraph), or build model manually, using fluent API.
The second scenario fits dynamic models for plugin-based applications, because you can discover models types, using custom algorithm, and call DbModelBuilder methods to "assembly" model.
is it possible to DbSet out of DbContext class is ASP.Net MVC code first?
In short, you can't use DbSet<TEntity> without DbContext.
Consider DbSet as a part of context (AFAIK, DbSet holds a reference to DbContext, which was used to create DbSet).
Since ASP .NET is all about stateless, usual approach is to create DbContext instance (or its unit-of-work-like wrapper), perform an action, dispose the context, and throw it away. Holding references to DbContext/DbSet as a state in web applications at least useless.

Injecting dependencies into AuthorizeAttribute in a class library

I've run into an interesting design issue with a class library I am writing. I have a custom implementation of the AuthorizeAttribute that I want clients to be able to use like this:
[Protected("permission_name")]
In the above code, PermissionAttribute inherits from AuthorizeAttribute and uses a local default (DefaultContext created using HttpContext).
Behind the scenes, the attribute uses a SecurityService to check users, roles and permissions against (the SecurityService itself uses a client-provided persistence service that they can wire up in the composition root of their app).
So my attributes need a reference to the SecurityService to function. Since Attribute constructors can only have compile-time constants, I cannot use constructor injection.
I don't want to force my clients to use a DI framework - they should be able to discover and wire up the necessary dependencies in their composition root without using an IoC library, if they so choose.
Here are my options:
Have the library use a singleton SecurityService.
Use property injection, which would work but
it would make the dependency seem optional, which it is not and
I don't know where I can do property injection in an MVC app on an authorize attribute.
A possible solution to 2. above is to do set an instance of SecurityService as a static property on the attribute at application startup and use a guard clause to prevent it from being set more than once, like this:
class ProtectedAttribute : ...
{
private static ISecurityService _SecurityService ;
public static ISecurityService SecurityService
{
get
{
return _SecurityService ;
}
set
{
if (_SecurityService != null)
throw new InvalidOperationException("You can only set the SecurityService once per lifetime of this app.") ;
_SecurityService = value ;
}
}
}
The SecurityService could be an abstract service facade so that it can be extended/replaced by a different implementation.
Is there a better way to solve this problem?
UPDATE: Adding some code to show how I am going to do it:
Add a public property on the attribute that returns the permission name:
public class ProtectedAttribute : ...
{
private string _Permission ;
public string Permission { get { return _Permission ; } /*...*/ }
public ProtectedAttribute(string permission) { /*...*/ }
}
Setup an authorization filter and configure dependency via Ninject (if using Ninject):
using Ninject.Web.Mvc.FilterBindingSyntax;
public class MyModule : Ninject.Modules.NinjectModule
{
public override void Load()
{
// mySecurityService instance below can have a singleton lifetime - perfect!
this.BindFilter<MyAuthorizationFilter>(FilterScope.Action, 0)
.WhenActionMethodHas<ProtectedAttribute>()
.WithConstructorArgument("securityService", mySecurityService)
.WithConstructorArgumentFromActionAttribute<ProtectedAttribute>("permission", p => p.PermissionName) ;
}
}
Ohhh it's...beautiful sniffle
With ASP.NET MVC 3 you could use constructor injection with action filters thanks to the new IFilterProvider. This way you no longer need to decorate your controller actions with action filters. You could apply them thanks to this interface and using a marker attribute.
And if you don't wanna bother implementing it manually you could always use an existing DI framework such as Ninject which provides a fluent way to define action filter dependencies.
My applications inherit from a base Application class that exposes the IOC container.
public interface IInjectableApplication
{
IUnityContainer Container { get; }
}
Then I have a base attribute class, which is aware of this
public abstract IocAwareActionFilterAttribute : ActionFilterAttribute{
protected T ResolveItem<T>(ResultExecutedContext context)
{
var app = context.HttpContext.ApplicationInstance as IInjectableApplication;
if (app == null) { throw new NullReferenceException("Application is not IInjectable."); }
T c = (T)app.Container.Resolve(typeof(T));
if (c == null) { throw new NullReferenceException(string.Format("Could not find injected {0}.", typeof(T).FullName)); }
return c;
}
}
While this is not true Injection, since Attributes aren't constructed 'normally', this provides a similar behavior. No reason it should not be adaptable to other IOCs

Categories

Resources