I am starting with MVC 3 and am planning in separating the model and the controllers into their own separate projects. I'll follow the suggestions made from this post for this:
asp.net mvc put controllers into a separate project
The purpose of separating them into separate projects is that there are chances that I may have to add a web service project to the solution and I’d like it to reuse the same functionality exposed by the controller project. So the solution will be formed of two view projects, WebServices and WebSite, the controller project and the model project.
I’d like to know if this is possible and if it’s a common scenario with MVC.
Update 1:
With your suggestions I agree and think it’s best to keep the view and the controllers together.
Would it be possible to have a hybrid of MVC and MVP? I have a feeling I am really overdoing things here so please let me know what you think.
So I would have:
1 – Web project with controllers.
2 – WebServices project
3 – Presenters/Interfaces.
4 – Model.
The controllers would then become the views in an MVP model. Also each web service would become a view in an MVP model.
For instance we could have the following, interface, presenter , controller.
public interface ICustomers {
string[] Customers{set;}
}
public class CustomerPresenter {
ICustomers view = null;
public CustomerPresenter(ICustomers view) {
this.view = view;
}
public void GetCustomers() {
view.Customers = new string[]{"Customer1","Customer2"};
}
}
public class CustomerController:ICustomers {
CustomerPresenter presenter = null;
public CustomerController() {
presenter = new CustomerPresenter(this);
}
private string[] customers = null;
public string[] Customers {
set { throw new NotImplementedException(); }
}
public void GetCustomers() {
presenter.GetCustomers();
//Return view.
}
}
The WebService would be a view in an MVP model.
public class CustomerWebService:ICustomers {
CustomerPresenter presenter = null;
public CustomerController() {
presenter = new CustomerPresenter(this);
}
[WebMethod]
public void GetCustomers() {
presenter.GetCustomers();
//Return response.
}
My projects are built specifically for the reason you stated, you want to implement a web service. I would not recommend separating the controllers because this is an actual part of the web project. What you actually want is around 3-4 different projects.
Repository/data layer (may contain your domain level models)
Domain Layer (optional)
Service layer. (Now this is where you can point your web service to very easily, all your re-usable logic should be here, not in the controller)
Web Layer. (Contains View Models, Views and Controllers)
I placed them in levels. Basically, the repository, domain and service layer are completely de-coupled, meaning you can use these libraries without a server or asp.net. A wpf application can just call to the service layer because the web layer is just for presentation purposes.
I am not sure it's common to separate the views and the controllers on their own projects. It might be but I haven't seen it personally.
The way I would split it initially is:
One project for views and controllers
One project for models
If and when you have the need to support different views you could update your controller to return something different depending on the type of request. It's common to have controllers that return different things for different clients (for example HTML vs JSON.)
Related
I've never worked with a .Net Core project before but have a history with .Net including MVC and entity framework. I'm working with a new .Net Core project which has five solution folders, EHA.PROJ.API, EHA.PROJ.DTO,EHA.PROJ.Repository, EHA.PROJ.Repository.Test and EHA.PROJ.Web. The EHA.PROJ.DTO folder has a number of files such as CategoryDTO.cs which looks like this
namespace EHA.PROJ.DTO
{
public class CategoryDescDTO
{
public int CategoryRef { get; set; }
public string CategoryName { get; set; }
}
}
I'm looking to set up a mapping arrangement to get the data from the EHA.PROJ.DTO files to the model files in my models folder in my EHA.PROJ.Web folder. I've been browsing as I've never done anything like this before as I've previously worked with data from a DAL folder using entity framework and connection done through connection strings. I'm guessing that there must be some process to map the data in my dbContext to connect the files in both folders. I did find some information on AutoMapper but was unsure how to implement it.
This arrangement with .Net Core is new to me so if anyone can help with any examples or point me in the right direction I would be grateful.
Your first problem is having your entities in your web project. Right off the bat, you have tight-coupling between the web project and your data layer, which then pretty much negates the point of all your other layers: DTO, repository, etc. You want to move out your entities and context into a true data layer (i.e. a class library project separate from your web project).
Then, you want to decide how far your data layer should extend. If the API is to feed the Website, then you want to actually remove all dependencies on the data layer from the web project. Your DTO project would be shared between the API and Web projects and your API would send/receive your DTOs, mapping back and forth from your entities under the hood.
However, if you're going to do that, then the repository project should just go away entirely. Just have your API work directly with EF and your entities. Your abstraction is the API itself; there is no need for another. The only reason to have the repository layer is if both the API and Web will both directly utilize the repositories, which isn't a very good pattern actually. You'll inevitably end up with a bunch of duplicated logic specific to each project.
Simply, the repository pattern is superfluous when using an ORM like EF. The ORM is your data layer. You're simply using a DAL provided by a third-party, rather than one you created yourself. The repository pattern only makes sense when working directly with SQL using something like ADO.NET directly. Otherwise, get rid of it.
Having an API is enough of an abstraction, if your goal is simply to hide the data layer. The website knows nothing of the underlying data source, and an API is really just a service layer that returns JSON over HTTP rather than object instances directly, i.e. the API is essentially your "repository" layer.
The situation can be improved even further by moving to a microservices-based architecture. With that, you essentially have multiple small, self-contained APIs that work with just one part of your domain or piece of functionality. Each can utilize EF directly, or an entirely different ORM, or even an entirely different stack. You could have APIs build on Node.js or python, etc. The website simply makes requests to the various services to get the data it needs and doesn't know or care how those services actually work.
I have been using Automapper for quite some time in .NET Core projects due to ease of use and built-in dependency injection.
Install from PM:
Install-Package AutoMapper
Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection
Register in the Startup.cs, ConfigureServices method:
services.AddAutoMapper(typeof(Startup));
Create a class to keep your mappings, e.g. MappingProfile.cs using Profile from automapper, you can define mappings.
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<Operator, OperatorDto>().ReverseMap();
}
}
}
The above mapping tells automapper that Operator can be mapped to OperatorDto and OperatorDto can be mapped to Operator.
In your controller, you can inject an IMapper
private readonly IMapper _mapper;
public OperatorsController(IMapper mapper)
{
_mapper = mapper;
}
and map values like below:
var dto = _mapper.Map<OperatorDto>(op); // Map op object to dto
var op = _mapper.Map<Operator>(dto); // Map dto to op object
Automapper offers custom mappings, should you need it.
While it is very easy to perform mappings with Automapper, you need to learn the framework.
I believe it is worth the effort to learn it as it will save you a lot of time writing mapping code in the future.
This article is a good reference to start: https://buildplease.com/pages/repositories-dto/
My suggestion is to have a DTO assembler that maps your model to the DTO object. So, you start with your DTO class:
namespace EHA.PROJ.DTO
{
public class CategoryDescDTO
{
public int CategoryRef { get; set; }
public string CategoryName { get; set; }
}
}
Then build the assembler:
public class CategoryDescAssembler {
public CategoryDescDTO WriteDto(CategoryDesc categoryDesc) {
var categoryDescDto = new CategoryDescDTO();
categoryDescDto.CategoryRef = categoryDesc.CategoryRef;
categoryDescDto.CategoryName = categoryDesc.CategoryName;
return categoryDescDto;
}
}
Now you implement the service to do all the work required to get the DTO object:
public class CategoryDescService : ICategoryDescService {
private readonly IRepository<CategoryDesc> _categoryDescRepository;
private readonly CategoryDescAssembler _categoryDescAssembler;
public CategoryDescService(IRepository<CategoryDesc> categoryDescRepository, CategoryDescAssembler categoryDescAssembler) {
_categoryDescRepository= categoryDescRepository;
_categoryDescAssembler= categoryDescAssembler;
}
public CategoryDescDTO GetCategoryDesc(int categoryRef) {
var categDesc = _categoryDescRepository.Get(x => x.CategoryRef == categoryRef);
return _categoryDescAssembler.WriteDto(categDesc);
}
}
With the interface looking like this:
public interface ICategoryDescService
{
CategoryDescDTO GetCategoryDesc(int categoryRef);
}
You would then need to add the service to your Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddTransient<ICategoryDescService, CategoryDescService>();
}
Now you can call your service from you view controller.
I have my business logic layer and data access layer in separated dll , I used active record design pattern to build my bll ... now I need to host my bll and dal in my mvc project ..
I tried to make classes in my models and inherits it's properties and methods from bll (which in another dll) but when I tried to assign base class to inherited one it gives me exception
//Customer class located in mvc model folder which inhireted from EgxCustomer that located in bll in another project
using Egx.EgxBusiness.Inventory;
namespace EgxNMWeb.Models
{
public class Customers:EgxCustomer
{
}
}
//here i try to assign list of EgxCustomer to list of customer
using Egx.EgxBusiness.Inventory;
namespace EgxNMWeb.Models
{
public class CPanelVM
{
Customers currentCustomer { get; set; }
List<Customers> AllNetwork { get; set; }
public CPanelVM()
{
AllNetwork = NMModel.GetCustomerNetwork(currentCustomer.CUST_CODE, Egx.EgxBusiness.Inventory.NM.REF_TYPE.ALL);
}
}
}
what can I do to use my bll which located in another project in my mvc project ?
There is no need for your model classes to be in Models folder. It is just a way to form your code structure (although your view must be in Views folder by default). You can directly use your business logic layer models in your controllers if you want.
I think in your project you can place view models in Models folder.
We are developing large MVC project and we have an intension to use HttpSessionStateWrapper (as well as HttpRequestWrapper, HttpResponseWrapper, etc) to add extended functionalities do this objects. It would be adding session messages, additional collections, html metadata with response - stuff like that, managable from controllers and accessible in the views when needed.
I have done it in a smaller project and it gennerally worked well, except some casting issues here and there, but it can be worked around by not using wrappers outside controllers or eventually views. Every controller would be a custom controller with a code like that:
public class Controller : System.Web.Mvc.Controller
{
public new CustomHttpResponse Response
{
get
{
return (CustomHttpResponse)HttpContext.Response;
}
}
public new CustomHttpRequestRequest
{
get
{
return (CustomHttpRequestRequest)HttpContext.Request;
}
}
//etc...
}
ContextWrapper would be created in a custom MvcHandler. Response, request and session wrappers would be created and taken from ContextWrapper .
Is this a good policy to use wrappers to extend functionalities, or they where intended only for creating testing mocks?
I have searched a lot for MVP, but I haven't found any good articles that help me understand it very well. Does anyone know of any good articles on the subject, with real-world examples to help me understand it better?
Thanks in advance.
Check out my answer to a so post, which may help you:
Is ASP.net Model View Presenter worth the time?
It goes through the differences between MVP and MVC, as often the two are contrasted.
Also, there's some helpful links, which show how to easily fit an MVP model to an existing ASP.Net website.
HTH
Here's a site devoted to doing mvp on asp.net: http://webformsmvp.com/
MVP as a pattern is kinda obsolete - MVC (which has a great asp.net framework and support) and MVVM (the de facto pattern of WPF) have largely taken over. In fact, Martin Fowler (MVP's inventor) has documented that the pattern really ought to be split into two patterns, Passive View and Supervising Controller on his site: http://martinfowler.com/eaaDev/ModelViewPresenter.html
ASP.NET Supervising Controller (Model View Presenter) From Schematic To Unit Tests to Code
Simplest example of MVP design patter of Asp.net
Model View Presenter with ASP.NET
Very Quick MVP Pattern to Use with ASP.NET
Edited
One more link:
Model View Presenter (MVP) Design Pattern with .NET - Winforms vs. ASP.NET Webforms
If you would like to dig more into this patter, take a look at the Web Client Software Factory 2010 tool.
This tool is basically used to create composite web applications (modules) but the views are implemented using the MVP pattern. If you are going to maintain traditional ASP.Net code or if you want to dig a little bit more in the ASP.Net paradigm, checking the source code of this tool is a great place to start.
This tool requires you to install a couple of extensions to Visual Studio, and after that, you can create a special web project that will implement the MVP for you, it will add contextual menus to Visual Studio to facilitate the tasks
Example:
Create a new project
Add a view with a presenter
Check the generated files
Check the default generated code:
public partial class MyNewView : Microsoft.Practices.CompositeWeb.Web.UI.Page, IMyNewViewView
{
private MyNewViewPresenter _presenter;
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
this._presenter.OnViewInitialized();
}
this._presenter.OnViewLoaded();
}
[CreateNew]
public MyNewViewPresenter Presenter
{
get
{
return this._presenter;
}
set
{
if (value == null)
throw new ArgumentNullException("value");
this._presenter = value;
this._presenter.View = this;
}
}
// TODO: Forward events to the presenter and show state to the user.
// For examples of this, see the View-Presenter (with Application Controller) QuickStart:
//
}
public interface IMyNewViewView
{
}
public class MyNewViewPresenter : Presenter<IMyNewViewView>
{
// NOTE: Uncomment the following code if you want ObjectBuilder to inject the module controller
// The code will not work in the Shell module, as a module controller is not created by default
//
// private IShellController _controller;
// public MyNewViewPresenter([CreateNew] IShellController controller)
// {
// _controller = controller;
// }
public override void OnViewLoaded()
{
// TODO: Implement code that will be executed every time the view loads
}
public override void OnViewInitialized()
{
// TODO: Implement code that will be executed the first time the view loads
}
// TODO: Handle other view events and set state in the view
}
Take a loot at the tool:
http://webclientguidance.codeplex.com/wikipage?title=Web%20Client%20Software%20Factory&referringTitle=Home
http://msdn.microsoft.com/en-us/library/ff648752.aspx
BTW, If you are going to start a new project, it should be a better idea to use the MVC, if you need to redactor an existing application, you can take as a base the implementation of the MVP in the Web Client Software Factory.
If you are interested, I think there's a work-through in order to convert an existing application to use the Web Client Software Factory
I am working on creating a Web site like www.hipmunk.com in ASP.NET web forms.
I need to pull the data from multiple API's and compare the rates and show the different rate options to the users.
What is the best way to achive this?
I am browsing around and see "Windows Workflow Foundation" may be an option.
Anyone got suggestions for me? I am just looking for architectural suggestions.
Thanks
EDIT: Multiple API: - Each OTA's have different type of API's but so far I have seen everyone supports the XML/JSON format
I'm assuming that you are trying to capture the same data from each of the services, but they may each have a different calling pattern, and they will definitely represent their results differently. One way to handle the differences in each of the services is to encapsulate them using the Strategy Pattern. You would have a standard results object, but based on the list of requested services, you would use a different strategy to fill each one.
public interface IResultsStrategy {
RateResults GetRateResults(SiteInfo site);
}
public class SpecificSiteStrategy {
public RateResults GetRateResults(SiteInfo site) {
//access the service through WCF, or whatever makes the most sense
//create a new RateResults object, and fill it with the appropriate data
}
}
public class AnotherSiteStrategy {
public RateResults GetRateResults(SiteInfo site) {
//access the service through a web request, or whatever makes the most sense
//create a new RateResults object, and fill it with the appropriate data
}
}
public class RateFetcher {
public IEnumerable<RateResults> GetRates() {
var rateResults = new List<RateResults();
foreach(SiteInfo site in SitesToFetch) {
IResultsStrategy strategy = GetStrategy(site);
rateResults.Add(strategy.GetRateResults(site));
}
return rateResults;
}
}