I am new to MVC programming. In normal OOP, where I have my class, I would just initiliaze and load data from database. In MVC, we have modules, how do I load up records from it?
Here is my current code for type UserAcount:
[Table("UserAccount")]
public class UserAccount {
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public string userName { get; set; }
public string email { get; set; }
public int companyID { get; set; }
}
Say that I have an user with name "testUser", how do I initialize on this record and get it's information? How do I do this:
UserAccount user = new UserAccount("tesetUser");
How and where shoulud I use this?
user = user.SingleOrDefault(u => u.userName.ToLower() == User.Identity.Name.ToLower());
You need to read up on Entity Framework. This is the default ORM that MVC uses. Simply:
If you don't have a project context, yet, create one:
public class MyProjectContext : DbContext
{
public MyProjectContext()
: base("name=ConnectionStringNameHere")
{
}
}
Add your models to your project context:
public class MyProjectContext : DbContext
{
...
public DbSet<SomeModel> SomeModels { get; set; }
public DbSet<SomeOtherModel> SomeOtherModels { get; set; }
# etc.
}
Update your database using Package Manager Console (TOOLS > Library Package Manager > Package Manager Console):
> update-database
(hit ENTER after typing that)
Now, to use your context in your controllers:
public class MyAwesomeController : Controller
{
private MyProjectContext db = new MyProjectContext();
public ActionResult Index()
{
var someModels = db.SomeModels;
return View(someModels);
}
public ActionResult GetSomeModel(int id)
{
var someModel = db.SomeModels.Find(id);
return View(someModel);
}
# other actions
}
In the simplest case, you should do this logic in your controller, which will pass the data to the view. However, MVC is meant for UI separation of concerns, so theoretically you should be doing this in your domain layer, which is called from your controller.
Here is a decent article from Jeff Atwood, however I disagree that the controller is the brains of the application. It is more of the brains of the UI...but that depends on how complex your code is. Dont create a domain layer if it is stupidly simple
In the MVC model, Controllers are responsible for processing HTTP requests.
Typically you would load your entity (e.g. UserAccount) in a controller action.
If you want to edit / update an entity, typically you would map the relevant fields to a model that reflects the UserAccount. A separate model is suggested because the needs of the UI are often somewhat different than the needs of the entity model. Having separate classes for each concern avoids polluting the entity model to satisfy the needs of the view.
Related
I'm developing a web app that contains a User entity that is derived from .NET Core's IdentityUser. Lets suppose there is another entity called Comment which has a relation to a user (the user who posted the comment):
public class User : IdentityUser
{
public string SomeExtraField { get; set; }
}
public class Comment
{
//Owner (Creator) of the feedback
public User User { get; set; }
//body of the comment
public string Body { get; set; }
}
Now suppose I have an API endpoint that returns all of the comments in the system. If I query for all comments and include the User relation, when the object gets serialized, everything in the User class is serialized and sent to the client (including the users hashed password, etc). Obviously I don't want this. So I've created a CommentService layer that grabs the Comments from a CommentRepository. From my understanding, the service layer should do the job of mapping the raw Comment object into a Comment DTO, which only contains data that should be sent to the client. I've defined a comment and user DTO like this:
public class UserOutput
{
public string Id { get; set; }
public string SomeExtraField { get; set; }
}
public class CommentOutput
{
public UserOutput User { get; set; }
public string Body { get; set; }
}
Then in my service layer I have something like the following:
//Fetch all comments
var list = await _repository.ListAsync();
//Map comments to DTO
var result = list.Select(x => new CommentOutput
{
Body = x.Body,
User = new UserOutput
{
Id = x.User.Id,
SomeExtraField = x.User.SomeExtraField,
}
});
This all seems to work great. However I can foresee one problem. Lets say I have a large system with Comments, Posts, Likes, Private Messages, etc. I can map them all in a similar fashion above. Then one day I decide to add another field to the UserOutput DTO. Now I have to go through potentially hundreds of mapping code like the sample above to map the new field properly, and whats worse is the compiler wont tell me if I've missed anything. I would like to have a function somewhere that maps a User to a UserOutput but I don't know where it should go.
I've seen some suggestions to put a constructor to the DTO that does the mapping:
public class UserOutput
{
public UserOutput(User user)
{
Id = user.Id;
SomeExtraField = user.SomeExtraField
}
public string Id { get; set; }
public string SomeExtraField { get; set; }
}
but I've seen people against this because it tightly couples the DTO with the Entity. I've also seen suggestions of using Auto Mapper but is also seems an equal amount of people are against it.
Where should I place code that can perform these DTO->entity and entity->DTO mappings so I don't repeat myself all over the place?
Try to check out AutoMapper.
This library will help you to map the Entity Class into the ViewModel.
The way to use it is pretty straightforward.
I'm having some confusion deciding where to store my data classes (models) in my MVC projects. My solutions generally follow the following format:
SolutionName
ProjectName.Web (project)
Controllers
Models
Scripts
Views
ProjectName.Core (project)
Services
Interfaces
Models
ProjectName.Repositories (project) - contains repositories (databases, XML storage).
ProjectName.Test (project)- contains unit tests.
My question is- where should the data classes be stored? In the traditional MVC project, the models are obviously stored in the models folder in the web project. But as I try to keep my solution loosely coupled by separating concerns into multiple projects, should the data models be stored in a different project, like my Core project?
View model classes that are designed simply to provide data to MVC views should be in the ProjectName.Web project Models folder according to standard ASP .NET MVC conventions.
That is not a requirement though and you can easily keep them in a separate assembly.
If you are talking about domain models, ORM entities or any type of non-UI classes that contain data; those probably belong in a separate project.
Generally speaking, I would keep everything in your core library that would be necessary if you wanted to re-use the core library in another project. Using this approach, you would isolate your "domain" model (http://en.wikipedia.org/wiki/Domain_model) to just the core layer and only the web-specific functionality would be in your website.
Let's say on the website you want a user to be logged in, but on a winforms app, the authentication would be handled by the user logging into the pc.
You could put that in your website only, and handle authentication completely separately in different applications, without putting it in your domain model.
Then you would keep only domain-specific models in the core library.
You would then create data models that either wrap the core entities, or or their own representations of combined entities. Then you could have the view models that utilize the data in the models to control the output.
Edit: Here is an example setup (though lengthy, I kept it as brief as possible to illustrate the separation).
//--------------- In your domain library:
public class DataRepository : IDataRepository {
public DataRepository() {
} // end constructor
public DataEntity GetData(DataRequest request) {
//get data based on DataRequest
return new DataEntity();
} // end function GetData
} // end class DataRepository
public class DataRequest {
public String RequestingUser {get; set;}
public Dictionary<String, object> Parameters {get;}
} // end class DataRequest
public class DataEntity {
public string Name {get; set;}
public Guid Id {get; set;}
public string SomeData {get; set;}
} // end class DataEntity
//--------------- In your web library:
public class UserRequest {
public string UserName {get; set;}
} // end class UserRequest
public class LandingPageViewModel {
public LandingPageViewModel() {
Data = new DataItemViewModel();
} // end constructor
public void FillData(DataEntity entity) {
Data.Name = entity.Name;
Data.DataValue = entity.SomeValue;
Data.ShowValue = !String.IsNullOrWhiteSpace(UserName);
} // end method FillData
public string UserName {get; set;}
public List<string> Messages {get; set;}
public DataItemViewModel Data {get; set;}
} // end class LandingPageViewModel
public class DataItemViewModel {
public string Name {get; set;}
public string DataValue {get; set;}
public bool ShowValue {get; set;}
} // end class DataItemViewModel
public class MyController : Controller {
private IDataRepository _repository;
public MyController(IDataRepository repository) {
_repository = repository;
} // end constructor
public ActionResult LandingPage(UserRequest user) {
ActionResult result = null;
DataRequest itemRequest = new DataRequest();
itemRequest.RequestingUser = user.UserName;
DataEntity myEntity = null;
myEntity = _repository.GetData(itemRequest);
if(myEntity != null) {
LandingPageViewModel viewModel = new LandingPageViewModel();
viewModel.UserName = user.UserName;
viewModel.FillData(myEntity);
result = View("LandingPage", viewModel);
} else {
result = View("Error");
} // end if/else
return result;
} // end action LandingPage
} // end class MyController
// In a view
<%# Page Title="" Language="VB" MasterPageFile="~/Views/Site.Master" Inherits="System.Web.Mvc.ViewPage(Of LandingPageViewModel)" %>
<div>
<%:Model.Name;%>
<%
if(Model.ShowValue) {
%>
<%:Model.DataValue;%>
<%
} // end if
%>
</div>
I am new to IoC and Repository Pattern. I was able to do some test project and it works. But, I am not so sure if what I implemented is a good practice. The test project I have created have all the repositories in place as well as a working interface with a dummy data. But what I want is that my project should not be able to know the concrete types of my models because the initial version should be implemented using MSSQL, and the second version would be a mix of MSSQL and NoSQL(for reads and logging). The models might have different properties or structures from MSSQL to NoSQL (or whatever i might use in the future)
So I tried to create an interface for each model:
public interface ISearchResult
{
string Id { get; set; }
string Name { get; set; }
string Description { get; set; }
string Url { get; set; }
}
And here's the repository:
public interface ISearchRepository<T> where T: class, ISearchResult
{
IEnumerable<T> Search<T>(string keyword, IEnumerable<string> regions, IEnumerable<string> industries,IEnumerable<string> countries, IEnumerable<string> cities, int offset);
}
And here's the service:
public interface ISearchService
{
IEnumerable<T> Search<T>(string keyword, IEnumerable<string> regions, IEnumerable<string> industries,IEnumerable<string> countries, IEnumerable<string> cities, int offset);
}
Because I want to have a working GUI even without MSSQL or NoSQL entities, I have created a View Model that inherited the ISearchResult:
public class SearchResultViewModel : ISearchResult
{
[Display(Name="Reference Id")]
public string Id { get; set; }
[Display(Name = "Company")]
public string Name { get; set; }
[Display(Name = "Description")]
public string Description { get; set; }
[Display(Name = "Website")]
public string Url { get; set; }
}
And here's how it looks on my controller:
[SearchQueryFilter]
[GeoTargetFilter]
public ActionResult Query(SearchQueryModel searchQuery)
{
searchQuery.Results = this._searchService.Search<SearchResultViewModel>(searchQuery.Keyword,searchQuery.Region, new List<string>() { searchQuery.Industries }, new List<string>() { searchQuery.Countries}, new List<string>() {searchQuery.City}, searchQuery.Offset)
.ToList<ISearchResult>();
return View(searchQuery);
}
And my view would look like this:
#foreach (SearchResultViewModel result in Model.Results)
{
//code to display
}
My question is: Is it fine to use this approach? I don't want my web application to be dependent on my data entities so that's why I came up of making my view models inherit an interface. And because I was new to IoC and Repository Pattern and only have a test project, I don't know if my solution would be more of a problem in the long run.
Any advise is highly appreciated.
You shouldn't need to implement an interface in your view model in order to create a separation between your web application and your data entities. Your view model should belong to your web application and should itself be independent of your data entity.
So, instead of:
_searchService.Search<SearchResultViewModel>(x);
You should have, in your controller:
var result = _searchService.Search<SomeEntity>(x);
var model = new SearchResultsViewModel
{
Name = result.Name,
Desc = result.Desc,
Url = result.Url
};
return View(model);
The view model belongs to the web application and is responsible for containing the data passed from controller to view (and back) - it should have nothing to do with your service layer (or any other layer of your application).
SomeEntity is a concrete class, in the form of whatever your search service exposes. Your controller will consume this in the same way as any other application would and then compile a view model for passing to and from views. You might even find that SomeEntity is more or less identical to SearchResultsViewModel initially; however, they are still distinct entities as the requirements of the view might change independently of the search service.
In my solution I have two projects.
Project 1 (Core)
Mapping SQL to DTO using Dapper
Project 2 (WebUI - ASP.NET MVC 4)
Here I use a ViewModel per View.
Examples of a Controller
[HttpGet]
public ActionResult Edit(int id)
{
// Get my ProductDto in Core
var product = Using<ProductService>().Single(id);
var vm = new ProductFormModel(product);
return View(vm);
}
Examples of a ViewModel
public class ProductFormModel : BaseViewModel, ICreateProductCommand
{
public int ProductId { get; set; }
public int ProductGroupId { get; set; }
public string ArtNo { get; set; }
public bool IsDefault { get; set; }
public string Description { get; set; }
public string Specification { get; set; }
public string Unit { get; set; }
public string Account { get; set; }
public decimal NetPrice { get; set; }
public ProductFormModel(int productGroupId)
{
this.ProductGroupId = productGroupId;
}
public ProductFormModel(ProductDto dto)
{
this.ProductId = dto.ProductId;
this.ProductGroupId = dto.ProductGroupId;
this.ArtNo = dto.ArtNo;
this.IsDefault = dto.IsDefault;
this.Description = dto.Description;
this.Specification = dto.Specification;
this.Unit = dto.Unit;
this.Account = dto.Account;
this.NetPrice = dto.NetPrice;
}
public ProductFormModel()
{
}
}
Explanation:
I'll get my DTOs in my controller using a service class in the project (Core).
Then i create my ViewModel and pass the DTO to the constructor in ViewModel.
I can also use this view to add a new Product because my ViewModel can take a empty constructor.
Does anyone have experience of this. I wonder if I am in this way will have problems in the future as the project gets bigger?
I know this has nothing to do with Dapper. But I would still like a good way to explain my solution.
I think you will be fine using your current approach. More importantly, start out like this and refactor if you start to encounter problems related to your object mapping code (instead of thinking too much about it beforehand).
Another way to organize mapping logic that I use sometimes is to employ extension methods. That way, the mapping code is kept separate from the view model itself. Something like:
public static class ProductMappingExtensions
{
public static ProductFormModel ToViewModel(this ProductDto dto)
{
// Mapping code goes here
}
}
// Usage:
var viewModel = dto.ToViewModel();
Yet another approach would be to use a mapping framework like AutoMapper - this is a good fit in particular if your mapping logic is simple (lots of 1:1 mappings between properties).
But again, start simple and refactor when you need to.
I realize that this is a little bit late answer, but maybe it will help someone in the future.
This way of doing mapping between objects breaks the 'S' of the SOLID principles, because the responsibility of the ViewModel is to prepare data in its properties to be ready to use by the view and nothing else, therefore, mapping objects should not be on it's responsibilities.
Another drawback of this way is that it also breaks the 'Loose Coupling' OO principle as you ViewModel is strongly coupled with your DTO.
I think, even when we are in the very first step of the project, there are some importants OO principles that we should never break, so using mapper classes, either auto (AutoMapper, ValueInjecter ...) or manual, is definitely better.
I have a set of model classes from another section of the application that cannot be modified. These do not have the validation attributes I need (RemoteAttribute for instance). How do I go about adding these? I can't add [MetadataTypeAttribute] to models.
To illustrate:
//in Models.dll
//remember: I can't modify this
public class Product
{
string Name { get; set; }
}
//in Web.dll
public class ProductController
{
// GET: /Product/
public ActionResult Index()
{
return View(new Product());
}
}
//what i need:
public class ProductMetadata
{
[Remote("Foo", "Bar")]
[RegularExpression]
string Name { get; set; }
}
Is this in any way possible without creating a ViewModel class or something of that sort?
Is this in any way possible without creating a ViewModel class
Assuming that a properly architected ASP.NET MVC application should always use view models you can only benefit from introducing them. In addition to solving this particular problem and hundreds of potential other problems you will have a properly architected ASP.NET MVC application :-)
Tying your model to a controller (which is what the RemoteAttribute will do) seems like a horrible idea in terms of reusability of this model in other applications.