I have my Entity Framework Entities split out into a separate class library from my web project and data access layer. In my controller I make a call to my repository to get an IEnumerable<RobotDog.Entities.Movie> and then try to serialize into json using JavaScriptSerializer but I get a circular reference even though I'm using the [ScriptIgnore] attribute.
IMPORTANT: Originally I had my entities, data access and web all under one project and I was able to successfully serialize my entites without a circular reference. When I created separate layers that's when I started having problems. I did not change any of the entities.
An example of one of my entities in the RobotDog.Entities namespace:
namespace RobotDog.Entities {
public class Character {
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[MaxLength(200)]
public string Name { get; set; }
public virtual Person Person { get; set; }
[ScriptIgnore]
public virtual Movie Movie { get; set; }
}
}
My controller:
namespace RobotDog.Web.Controllers {
public class MoviesController : Controller {
private UnitOfWork _unitOfWork = new UnitOfWork();
[HttpGet]
public ActionResult Index() {
var user = Membership.GetUser(User.Identity.Name);
if(user != null) {
var movies = _unitOfWork.UserMovieRepository.Get(u => u.UserId == (Guid) user.ProviderUserKey).Select(m => m.Movie);
var serializer = new JavaScriptSerializer();
var json = serializer.Serialize(movies);
return View(json);
}
return View();
}
}
}
My Repository:
namespace RobotDog.DataAccess.Movies {
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class {
internal MovieContext Context;
internal DbSet<TEntity> DbSet;
public Repository(MovieContext context) {
if (context == null)
throw new ArgumentNullException("context");
Context = context;
DbSet = Context.Set<TEntity>();
}
public virtual IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> predicate = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null ) {
IQueryable<TEntity> query = DbSet;
if (predicate != null)
query = query.Where(predicate);
return orderBy != null ? orderBy(query).ToList() : query.ToList();
}
}
}
Maybe kinda late response, but I had similar problem with POCO Classes for Entity Framework Code-Firts. The problem was that may properties were declared as virtual. In this case EF creates proxy class which overrides the virtual property. It seems that ScriptIgnore attribute is not by default applied on overriden properties, unless you use it like this:
[ScriptIgnore(ApplyToOverrides=true)]
Circular object graphs cannot be JSON serialized. And when you give it a second thought it actually makes sense. The correct way to handle this is to use view models. You should never pass your domain entities directly to your views. Always define a view model containing only the necessary properties that you want to be exposed.
I am sure that the client consuming this JSON doesn't care about having this circular object graph. So simply define a view model breaking this circular dependency and including only the properties you need.
Then all you have to do is map your domain model to the view model and pass this view model to a JsonResult (yeah that's another issue in your code - you are manually JSON serializing and writing plumbing code in your controller action instead of delegating this to the framework).
So:
[HttpGet]
public ActionResult Index()
{
var user = Membership.GetUser(User.Identity.Name);
if(user != null)
{
IEnumerable<Movie> movies = _unitOfWork
.UserMovieRepository.Get(u => u.UserId == (Guid) user.ProviderUserKey)
.Select(m => m.Movie);
IEnumerable<MovieViewModel> moviesVm = ... map the domain model to your view model
return Json(moviesVm, JsonRequestBehavior.AllowGet);
}
// return an empty movies array
var empty = Enumerable.Empty<MovieViewModel>();
return Json(empty, JsonRequestBehavior.AllowGet);
}
The important thing you should be focusing right now on is defining the MovieViewModel class which will contain only the information that you want to expose to the client as JSON. Break all circular references. Feel free to have additional view models that this main view model is referencing in order to map other entities.
And most importantly : never pass your domain models to the view. Always define view models. This way your application is completely independent of the underlying data access technology you are using. You could modify your DAL layer as much as you like without impacting the UI part because this UI is represented by view models.
Related
This question has been asked before on SO and elsewhere in the context of MVC3 and there are bits and bobs about it related to ASP.NET Core RC1 and RC2 but niot a single example that actually shows how to do it the right way in MVC 6.
There are the following classes
public abstract class BankAccountTransactionModel {
public long Id { get; set; }
public DateTime Date { get; set; }
public decimal Amount { get; set; }
public readonly string ModelType;
public BankAccountTransactionModel(string modelType) {
this.ModelType = modelType;
}
}
public class BankAccountTransactionModel1 : BankAccountTransactionModel{
public bool IsPending { get; set; }
public BankAccountTransactionModel1():
base(nameof(BankAccountTransactionModel1)) {}
}
public class BankAccountTransactionModel2 : BankAccountTransactionModel{
public bool IsPending { get; set; }
public BankAccountTransactionModel2():
base(nameof(BankAccountTransactionModel2)) {}
}
In my controller I have something like this
[Route(".../api/[controller]")]
public class BankAccountTransactionsController : ApiBaseController
{
[HttpPost]
public IActionResult Post(BankAccountTransactionModel model) {
try {
if (model == null || !ModelState.IsValid) {
// failed to bind the model
return BadRequest(ModelState);
}
this.bankAccountTransactionRepository.SaveTransaction(model);
return this.CreatedAtRoute(ROUTE_NAME_GET_ITEM, new { id = model.Id }, model);
} catch (Exception e) {
this.logger.LogError(LoggingEvents.POST_ITEM, e, string.Empty, null);
return StatusCode(500);
}
}
}
My client may post either BankAccountTransactionModel1 or BankAccountTransactionModel2 and I would like to use a custom model binder to determine which concrete model to bind based on the value in the property ModelType which is defined on the abstract base class BankAccountTransactionModel.
Thus I have done the following
1) Coded up a simple Model Binder Provider that checks that the type is BankAccountTransactionModel. If this is the case then an instance of BankAccountTransactionModelBinder is returned.
public class BankAccountTransactionModelBinderProvider : IModelBinderProvider {
public IModelBinder GetBinder(ModelBinderProviderContext context) {
if (context == null) throw new ArgumentNullException(nameof(context));
if (context.Metadata.IsComplexType && !context.Metadata.IsCollectionType) {
var type1 = context.Metadata.ModelType;
var type2 = typeof(BankAccountTransactionModel);
// some other code here?
// tried this but not sure what to do with it!
foreach (var property in context.Metadata.Properties) {
propertyBinders.Add(property, context.CreateBinder(property));
}
if (type1 == type2) {
return new BankAccountTransactionModelBinder(propertyBinders);
}
}
return null;
}
}
2) Coded up the BankAccountTransactionModel
public class BankAccountTransactionModelBinder : IModelBinder {
private readonly IDictionary<ModelMetadata, IModelBinder> _propertyBinders;
public BankAccountTransactionModelBinder(IDictionary<ModelMetadata, IModelBinder> propertyBinders){
this._propertyBinders = propertyBinders;
}
public Task BindModelAsync(ModelBindingContext bindingContext) {
if (bindingContext == null) throw new ArgumentNullException(nameof(bindingContext));
// I would like to be able to read the value of the property
// ModelType like this or in some way...
// This does not work and typeValue is...
var typeValue = bindingContext.ValueProvider.GetValue("ModelType");
// then once I know whether it is a Model1 or Model2 I would like to
// instantiate one and get the values from the body of the Http
// request into the properties of the instance
var model = Activator.CreateInstance(type);
// read the body of the request in some way and set the
// properties of model
var key = some key?
var result = ModelBindingResult.Success(key, model);
// Job done
return Task.FromResult(result);
}
}
3) Lastly I register the provider in Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options => {
options.ModelBinderProviders.Insert(0, new BankAccountTransactionModelBinderProvider());
options.Filters.Add(typeof (SetUserContextAttribute));
});
The whole thing seems OK in that the provider is actually invoked and the same is the case for the model builder. However, I cannot seem to get anywhere with coding the logic in BindModelAsync of the model binder.
As already stated by the comments in the code, all that I'd like to do in my model binder is to read from the body of the http request and in particular the value of ModelType in my JSON. Then on the bases of that I'd like to instantiate either BankAccountTransactionModel1 or BankAccountTransactionModel and finally assign values to the property of this instance by reading them of the JSON in the body.
I know that this is a only a gross approximation of how it should be done but I would greatly appreciate some help and perhaps example of how this could or has been done.
I have come across examples where the line of code below in the ModelBinder
var typeValue = bindingContext.ValueProvider.GetValue("ModelType");
is supposed to read the value. However, it does not work in my model binder and typeValue is always something like below
typeValue
{}
Culture: {}
FirstValue: null
Length: 0
Values: {}
Results View: Expanding the Results View will enumerate the IEnumerable
I have also noticed that
bindingContext.ValueProvider
Count = 2
[0]: {Microsoft.AspNetCore.Mvc.ModelBinding.RouteValueProvider}
[1]: {Microsoft.AspNetCore.Mvc.ModelBinding.QueryStringValueProvider}
Which probably means that as it is I do not stand a chance to read anything from the body.
Do I perhaps need a "formatter" in the mix in order to get desired result?
Does a reference implementation for a similar custom model binder already exist somewhere so that I can simply use it, perhaps with some simple mods?
Thank you.
I started refactoring an ASP.Net 5 web application which uses MVC 6 and Entity Framework 7 when I was wondering about some points. My controllers currently use the DbContext implementation via dependency injection to fill the view models and return them for rendering with the view. Like:
public class UserController : Controller
{
[FromServices]
public MyContext myContext { get; set; }
//route which renders all users
public IActionResult Index()
{
var users = myContext.User.OrderBy(u => u.Name);
List<UserIndexViewModel> v = new List<UserIndexViewModel>();
foreach (var item in users)
{
v.Add(new UserIndexViewModel { Name = item.Name, City = item.City, DateOfBirth = item.DateOfBirth });
}
return View(v);
}
//route to edit user
public async Task<ActionResult> Edit(int id)
{
User user = await FindUserAsync(id);
UserEditViewModel v = new UserEditViewModel { Name = user.Name, City = user.City };
return View(v);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Update(int id, UserEditViewModel userModel)
{
User user = await FindUserAsync(id);
try
{
user.Name = userModel.Name;
user.City = userModel.City;
myContext.User.Attach(user);
myContext.Entry(user).State = EntityState.Modified;
await myContext.SaveChangesAsync();
return RedirectToAction("Index");
}
catch (Exception)
{
ModelState.AddModelError(string.Empty, "Unable to save changes.");
}
return View(userModel);
}
private Task<User> FindUserAsync(int id)
{
return myContext.User.SingleOrDefaultAsync(u => u.UserId == id);
}
}
I did some research and I found some blog posts (like this) which asks to keep controllers clean. Ok.. why not?
I started creating a kind of view model builder to put the logic out of the controller methods over to the view model builder. In the above linked article is a hint to create for each view model a own view-model-builder class - which makes sense in my eyes.
For the model User exist two views and thus two view models (UserIndexViewModel and UserEditViewModel). When I create the related view-model-builder classes they should derivate from the same (abstract) class because it could be that both child classes needs a helper method (like FindUserAsync() - it is not the case in my example but just imagine). So I would have a construct like the following:
public interface IViewModelBuilder<TController, TViewModel>
{
TViewModel Build(TController controller, TViewModel viewModel);
Task<TViewModel > BuildAsync(TController controller, TViewModel viewModel);
}
public abstract class UserViewModelBuilder<TViewModel> : IViewModelBuilder<UserController, TViewModel> { ... }
public class UserIndexViewModelBuilder : SiteViewModelBuilder<UserIndexViewModel> { ... }
public class UserEditViewModelBuilder : SiteViewModelBuilder<UserEditViewModel> { ... }
This mentioned function which is needed by multiple view model builders of one model should be implemented in the abstract class (UserViewModelBuilder in my case), right?
I did it like this:
public abstract class UserViewModelBuilder<TViewModel> : IViewModelBuilder<UserController, TViewModel>
{
[FromServices]
public MyContext myContext { get; set; }
public abstract TViewModel Build(UserController controller, TViewModel viewModel);
public abstract Task<TViewModel> BuildAsync(UserController controller, TViewModel viewModel);
public Task<User> FindUserAsync(int id)
{
return myContext.User.SingleOrDefaultAsync(u => u.UserId == id);
}
}
So with this abstract class I can create the implementation of UserIndexViewModelBuilder and UserEditViewModelBuilder classes as well as for example UserDeleteViewModelBuilder and UserCreateViewModelBuilder classes in future...
Now the question:
Is this a right approach to separate the logic from the controller? If yes, do I need a kind of factory for all view model builders which can be accessed via DI in all my controllers? If it is the way which is kind of best practice for MVC applications. Is there something different to the mentioned guide which can/should be used in MVC 6 apps?
Is the abstract class the right place to call the DbContext implementation via DI? It feels not good for me.
Some other points which I missed? Some if-statements for checking response were removed from the UserController snipped for better readability.
Thank you! :-)
Hi I have model class which is written in MVC.I am using Ef database first approach. In model class I have some queries which deals with database. I have following questions :
1) Is it right way to use database related queries in Model and call that in controller or view?
2)If yes where I should call this model? In Controller or in view ??
3)How I should call this model? Say for example I have class called class1.cs in model.How I should call this model?
Your model contains classes that define the different objects troughout your project. This includes properties with their basic information and methods to perform actions on this object.
1)
Do you really need queries? Why not use the Entity Framework to do it for you? Create the mapping for your domain classes (either trough annotations or fluent api) and use the DbContext to retrieve and save the data stored in your database
2)
Ideally people create repositories that are injected into your controllers (Dependency Injection). These repositories can for example contain something like GetPersonById(int id). Inside this method there would be two things:
Perform an action on the domain object
Save it to the DbContext
For example:
public void Subscribe(int userID, Show show) {
var user = GetUserByID(userID);
if (!user.IsSubscribedTo(show.ShowID)) {
user.Subscribe(show);
_dbContext.SaveChanges();
}
}
Controller -> Method call in repository -> Perform action on corresponding domain object -> Save changes to the database
If you need something that doesn't require an object mutation, it's even more simple:
public User GetUserByID(int id) {
return _dbContext.Users.FirstOrDefault(x => x.ID == id);
}
3)
Trough repositories (see above). Your DbContext will have a bunch of DbSets that contain objects that correspond with every data entry in your database. Trough repositories you can work with these objects and manipulate them. When you call the DbContext.SaveChanges() method, it will look at what has changed in these lists and commit the changes to your database.
Repository example:
class User {
public int ID { get; set; }
public string Name { get; set; }
}
class DatabaseContext : DbContext {
public DbSet<User> Users { get; set; }
}
public interface IUserRepository {
User GetUserByID (int id);
bool UsernameExists (string name);
}
public class UserRepository : IUserRepository {
private DatabaseContext _db;
public UserRepository(DatabaseContext db){
_db = db;
}
public User GetUserByID(int id) {
return _db.Users.FirstOrDefault(x => x.ID == id);
}
public User GetUserByUsername(string username) {
return _db.Users.FirstOrDefault(x => x.Name == username);
}
}
public class UserController : Controller {
private IUserRepository _userRepository;
public UserController(IUserRepository userRepository) {
_userRepository = userRepository;
}
public ActionResult Details(int id){
return View(_userRepository.GetUserByID(id);
}
}
// Ninject settings (install this extension, you want it):
private void AddBindings(){
kernel.Bind<DatabaseContext>().ToSelf().InSingletonScope();
kernel.Bind<IUserRepository>().To<UserRepository>().InRequestScope();
}
You could use some sort of Unit Of Work pattern which you inject in your controller constructor using an inversion of control container (IOC), for instance autofac.
Your unit of work class could hold a reference to repositories, where you would query/insert your data.
Roughly;
public class BackendController : Controller
{
private UnitOfWork _worker;
public BackendController(UnitOfWork worker)
{
this._worker = worker;
}
public ActionResult Admin()
{
var items = _worker.MyRepository.GetAll();
return View(items);
}
}
public class UnitOfWork
{
private ContentRepository _contentRepository;
public UnitOfWork()
{
}
public ContentRepository MyRepository
{
get
{
if (_contentRepository != null)
return _contentRepository;
else
return _contentRepository = new ContentRepository();
}
}
}
public class ContentRepository
{
// holds an object context and methods to retrieve and put data (EF or similar)
}
You would have to register your instance with the IOC container in global.asax, application_start for example, something like this (Using autofac as IOC):
UnitOfWork worker = new UnitOfWork();
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterInstance(worker).SingleInstance();
var container = builder.Build();
...
1) Is it right way to use database related queries in Model and call that in controller or view?
I would recommend not directly accessing the database in your model classes, as you have to remember that MVC is strictly a presentation layer pattern. If you do put your database access logic in your model classes, then you will not be able to have any other client use this functionality, such as a web service. Instead have logic that translates your business objects, defined outside of your ASP.NET MVC project, into your ASP.NET MVC model classes.
This is where the power of n-tier architecture shines, if you create a business and data-access layer, then I could write an ASP.NET MVC front-end, WebForms front-end, WPF front-end, WinForms front-end and all of them could access data using the same service. By putting the logic into the ASP.NET MVC model classes, then you are effectively forcing any other client to duplicate that logic again in their classes.
I'm using the Fluent Validation framework in my ASP.net MVC 3 project. So far all of my validations have been very simple (make sure string is not empty, only a certain length, etc.) but now I need to verify that something exists in the database or not.
Should Fluent Validation be used in this case?
If the database validation should be done using Fluent Validation, then how do I handle dependencies? The validator classes are created automatically, and I would need to somehow pass it one of my repository instances in order to query my database.
An example of what I'm trying to validate might:
I have a dropdown list on my page with a list of selected items. I want to validate that the item they selected actually exists in the database before trying to save a new record.
Edit
Here is a code example of a regular validation in Fluent Validation framework:
[Validator(typeof(CreateProductViewModelValidator))]
public class CreateProductViewModel
{
public string Name { get; set; }
public decimal Price { get; set; }
}
public class CreateProductViewModelValidator : AbstractValidator<CreateProductViewModel>
{
public CreateProductViewModelValidator()
{
RuleFor(m => m.Name).NotEmpty();
}
}
Controller:
public ActionResult Create(CreateProductViewModel model)
{
if(!ModelState.IsValid)
{
return View(model);
}
var product = new Product { Name = model.Name, Price = model.Price };
repository.AddProduct(product);
return RedirectToAction("Index");
}
As you can see, I never create the Validator myself. This works because of the following line in Global.asax:
FluentValidation.Mvc.FluentValidationModelValidatorProvider.Configure();
The problem is that now I have a validator that needs to interact with my database using a repository, but since I'm not creating the validators I don't know how I would get that dependency passed in, other than hardcoding the concrete type.
Can't you just create your own validation method where in you would kick-off the database validation?
RuleFor(m => m.name)
.Must(BeInDatabase)
private static bool BeInDatabase(string name)
{
// Do database validation and return false if not valid
return false;
}
I'm using FluentValidation for DataBase validations. just pass the Validation class the session in the Ctor. and do the validation inside the action something like:
var validationResult = new ProdcutValidator(session).Validate(product);
Update: Based on your example I add my example...
public class CreateProductViewModel
{
public string Name { get; set; }
public decimal Price { get; set; }
}
public class CreateProductViewModelValidator : abstractValidator<CreateProductViewModel>
{
private readonly ISession _session;
public CreateProductViewModelValidator(ISession session)
{
_session = session;
RuleFor(m => m.Name).NotEmpty();
RuleFor(m => m.Code).Must(m, Code => _session<Product>.Get(Code) == null);
}
}
Controller:
public ActionResult Create(CreateProductViewModel model)
{
var validator = new CreateProductViewModelValidator();
var validationResult =validator.Validate(model);
if(!validationResult.IsValid)
{
// You will have to add the errors by hand to the ModelState's errors so the
// user will be able to know why the post didn't succeeded(It's better writing
// a global function(in your "base controller" That Derived From Controller)
// that migrate the validation result to the
// ModelState so you could use the ModelState Only.
return View(model);
}
var product = new Product { Name = model.Name, Price = model.Price };
repository.AddProduct(product);
return RedirectToAction("Index");
}
Second update:
If you insist using parameterless constructor you will have to use some Inversion Of control container, a static class that is something like the Factory of your objects.
use it like this:
public class CreateProductViewModelValidator : abstractValidator<CreateProductViewModel>
{
private readonly ISession _session;
public CreateProductViewModelValidator()
{
_session = IoC.Container.Reslove<ISession>();
RuleFor(m => m.Name).NotEmpty();
RuleFor(m => m.Code).Must(m, Code => _session<Product>.Get(Code) == null);
}
}
You can find many IoC containers, most famous are Windsor and Ninject,
You will need to register- instruct the container once to resolve all the ISession to return your's session object.
The other way this could work for you is using Constructor injection. While this method isn't as clear cut as using an IoC library, it may help if you have a static way of accessing or fetching your session.
public class CreateProductViewModelValidator
{
private ISession _session;
public CreateProductViewModelValidator()
:this(SessionFactory.GetCurrentSession()) //Or some other way of fetching the repository.
{
}
internal CreateProductViewModelValidator(ISession session)
{
this._session = session;
RuleFor(m => m.Name);//More validation here using ISession...
}
}
I have been spending quite a bit of time thinking about this exact same issue. I am using ninject to inject my repository into my web UI layer so that my web UI only accesses the database through an interface.
I am wanting to be able to validate things that access the database such as checking for duplicate names and hence my validation needs to access the injected repository. I think that the best way to do this is to just setup Fluent Validation via the manual method rather than the MVC integrated way. For Example:
Create your validation Class (can pass in repository Interface):
public class CategoryDataBaseValidation : AbstractValidator<CategoryViewModel>
{
private IRepository repository;
public CategoryDataBaseValidation (IRepository repoParam)
{
repository = repoParam;
RuleFor(Category => Category.Name).Must(NotHaveDuplicateName).WithMessage("Name already exists");
}
private bool NotHaveDuplicateName(string name)
{
List<Category> c = repository.Categories.ToList(); //Just showing that you can access DB here and do what you like.
return false;
}
}
}
Then in your controller you can just create an instance of above class and pass in the repository (that ninject would have injected in the controller constructor)
[HttpPost]
public ActionResult Create(CategoryViewModel _CategoryViewModel )
{
CategoryDataBaseValidation validator = new CategoryDataBaseValidation (repository);
ValidationResult results = validator.Validate(_CategoryViewModel );
if (results.IsValid == false)
{
foreach (var failure in results.Errors)
{
//output error
}
}
return View(category);
}
Both the above files can live in the Web UI project and you can then also just use the standard MVC DataAnnotations for client side validation.
Just thought that I would put this up for comment / help someone.
I've been using the repository pattern described in Bob Cravens blog to create my application, but I'm a bit new and still finding my way around it. I want to inject my DataService object into the constructor of my ViewModel so I can create a SelectList object, and create a drop down box in my view. However I can't seem to get the bindings to work, every time I create the ViewModel it looks for / executes the parameterless constructor! I've tried various ways using answers here on SO but to no avail. Help would be greatly appreciated.
ViewModel:
public class ServerCreateViewModel
{
public SelectList Companies { get; private set; }
public ServerCreateViewModel()
{
}
public ServerCreateViewModel(DataService _dataService)
{
Companies = new SelectList(_dataService.Companies.All(), "Id", "CompanyName");
}
Ninject module:
Bind<DataService>().ToSelf()
.InRequestScope();
var _dataService = Kernel.Get<DataService>();
Bind<ServerCreateViewModel>()
.ToSelf()
.WithConstructorArgument("_dataService", _dataService);
//Bind<ServerCreateViewModel>()
// .ToSelf()
// .WithConstructorArgument("_dataService", ctx => ctx.Kernel.Get<DataService>());
Controller:
public ActionResult Create(ServerCreateViewModel viewModel)
{
return View(viewModel);
}
You shouldn't be doing that!
View Models (all models, in fact) should be just buckets with some data. They should not depend on any business logic, services, etc.
It is controller's responsibility to populate models and pass them to views.
public class ServerCreateViewModel
{
public SelectList Companies { get; private set; }
}
public ActionResult Create()
{
var viewModel = new ServerCreateViewModel
{
Companies = new SelectList(_dataService.Companies.All(), "Id", "CompanyName")
};
return View(viewModel);
}
DataService should be injected into the controller, not view model.