ASP.NET mvc linq 2 SQL model : where is the business logic? - asp.net

I'm building a first MVC app in ASP.NET and I'm using link2SQL model to work with data.
All tutorials on the microsoft site let you write LINQ code in the controller to get data and pass it to the view, like this:
Function Index() As ActionResult
Dim datacontext As New ErrorVaultDataContext
Dim questions = From q In datacontext.Questions
Where q.fk_status_id = 1
Order By q.date Descending
Select q
Return View(questions)
End Function
That works, but it's confusing me on where to place my business logic. I would like to implement business logic like "can this user get this data?" in this simple example.
Does anyone know how this works in conjunction with linq 2 SQL?

This LINQ query is the business logic. The problem is that in this example it is hardcoded in the controller thus making it tied to the database.
You could abstract it into an interface which will perform this query so that your controller is no longer dependent on a datacontext. Then you could have an implementation of this interface which will perform the actual data access:
Public Interface IBusinessRepository
Function GetQuestions(statusId As Integer) As IEnumerable(Of Question)
End Interface
Public Class BusinessRepositorySql
Implements IBusinessRepository
Public Function GetQuestions(statusId As Integer) As IEnumerable(Of Question) Implements IBusinessRepository.GetQuestions
' TODO: Perform the data access here
Throw New NotImplementedException()
End Function
End Class
Then the controller could use the business logic (In this case all it needs is to get questions filtered by some condition):
Public Class HomeController
Inherits Controller
Private ReadOnly _repository As IBusinessRepository
Public Sub New(repository As IBusinessRepository)
_repository = repository
End Sub
Public Function Index() As ActionResult
Dim questions = _repository.GetQuestions(1)
Return View(questions)
End Function
End Class
Then you could build a custom controller factory that will inject the proper implementation in the controller.

you need to look at patterns beyond MVC for instance the Repository pattern may be a good place to put the LIN2SQL then build a BLL (Business Logic Layer) between that and your controllers to do the business logic

I agree with Pharabus, regardless of which presentation layer you're using (webforms vs. mvc) you probably want to encapsulate your business logic in its own layer. That way your controller actions would make calls to the service/business layer objects instead of making use of the ORM (EF/linq2sql) context directly.

Related

Re-factor my DAL code to a Domain Driven Design or more modern design (C# 3.5)?

The development is limited to Visual Studio 2010 (Client approved software). We need to access the data through stored procedures. I want to avoid making it too complex with an aggressive schedule. Most of the design I see involve EF and LINQ, Not sure how to design for procs?
I want to create a separate code library project (used Web UI):
Application.Domain
- Interact get/put stored procedures, entities
Application.Web
- containing Web UI (JQuery, AJAX), WCF Service
Can anyone give me sample code on how to approach the Application.Domain?
Examples, I have read:
http://www.developer.com/net/dependency-injection-best-practices-in-an-n-tier-modular-application.html
http://www.kenneth-truyers.net/2013/05/12/the-n-layer-myth-and-basic-dependency-injection/
DAL\AppDAL.cs:
public static IEnumerable<TasCriteria> GetTasCriterias()
{
using (var conn = new SqlConnection(_connectionString))
{
var com = new SqlCommand();
com.Connection = conn;
com.CommandType = CommandType.StoredProcedure;
com.CommandText = "IVOOARINVENTORY_GET_TASCRITERIA";
var adapt = new SqlDataAdapter();
adapt.SelectCommand = com;
var dataset = new DataSet();
adapt.Fill(dataset);
var types = (from c in dataset.Tables[0].AsEnumerable()
select new TasCriteria()
{
TasCriteriaId = Convert.ToInt32(c["TasCriteriaId"]),
TasCriteriaDesc= c["CriteriaDesc"].ToString()
}).ToList<TasCriteria>();
return types;
}
}
Models\TasCriteria.cs:
public class TasCriteria
{
public int TasCriteriaId { get; set; }
public string TasCriteriaDesc { get; set; }
}
Service\Service.svc:
[OperationContract]
[WebInvoke(ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.WrappedRequest, Method = "GET")]
public List<TasCriteria> GetTasCriteriaLookup()
{
var tc = InventoryDAL.GetTasCriterias();
return tc.ToList();
}
If you:
are running on a tight schedule
have most of the business logic already on the DB side via sprocs/views
have not worked with EF before
I suggest you take a look at the Microsoft Enterprise Library, especially the Data Application Block. It will simplifie ALL of your DAL functionality (without using any ORM framework) and it follows the dependency inversion principle with the help of Unity which is a dependency injection container from Microsoft.
Some helpfull Data Application Block concepts:
Output Mapper
An output mapper takes the result set returned from a database (in the
form of rows and columns) and converts the data into a sequence of
objects.
// Create and execute a sproc accessor that uses default parameter and output mappings
var results = db.ExecuteSprocAccessor<Customer>("CustomerList", 2009, "WA");
Read the whole Retrieving Data as Objects topic.
Parameter Mapper
A parameter mapper takes the set of objects you want to pass to a
query and converts each one into a DbParameter object.
// Use a custom parameter mapper and the default output mappings
IParameterMapper paramMapper = new YourCustomParameterMapper();
var results = db.ExecuteSprocAccessor<Customer>("Customer List", paramMapper, yourCustomParamsArray);
For Entity generation I would try to use this tool. It builds a POCO class from a resultset returned by a sproc. I have not tried this tool yet and maybe there are better alternatives but it is something to get you start with, so you dont have to do this by hand.
If you are using .NET 3.5 then you have to work with Enterprise Library 5.0.
I hope this will steer you in the right direction.
first and foremost, make sure you abstract you DAL using dependency injection such as ninject or unity (or many others freely available). it is quite possible to have your DAL loosely coupled so that if you decide later on the EF (or any other ORM) is not the best course, changing it would no cost blood...
you do NOT want to have an AppDAL class with static methods to call the SP. at the very least add an interface and use injection, if only for the sake of unit testing.
whether you'll use EF or Nhibernate or any other ORM, that decision should be encapsulated in your DAL and not leak into other layers. the domain layer should use interfaces for repository classes from the DAL (and those contain references to the chosen ORM or data access classes).
these repositories will call the stored procedures and return your model classes (POCOs).
in one of my recent project we had this interface to provide basic CRUD operations:
public interface IRepository<T> where T : DomainEntity
{
T Get(Int64 id);
void SaveOrUpdate(T entity);
void Delete(T entity);
IQueryable<T> Find();
}
DomainEntity is a very simple class that all model clasess inherit.
In the rare cases where we needed to use stored procedures I'd create an additional interface that provides a GetXXXEntity method (1 or more), that would do the actual call to the SP.
so, when I need to get an entity from the DB using it's Id, it would look like:
_diWrapper.GetRepository<Person>().Get(id);
_diWrapper.GetRepository<Order>().Get(id);
_diWrapper is my wrapper for the dependency injection container (ninject in this case). I used a wrapper so I could easily replace ninject with something else if needed.
in common cases where I need to use linq:
_diWrapper.GetRepository<Person>().Find().Where(q => q.Name == "Jack").ToList();
the important thing was that I could replace Nhibernate with anything else rather quickly.
I strongly recommend you look at Fluent NHibernate, as it provides a simple solution that does not require much coding.
EDIT: here's an example of the repository class implementing the IRepository interface:
public class NhibernateRepository<T> : IRepository<T> where T : DomainEntity, new()
{
private ISession _session;
public NhibernateRepository()
{
_session = BaseNHibernateHelper<NHibernateHelper>.GetCurrentSession();
}
public T Get(Int64 id)
{
return _session.Get<T>(id);
}
public void SaveOrUpdate(T entity)
{
_session.SaveOrUpdate(entity);
}
public void Delete(T entity)
{
_session.Delete(entity);
}
public IQueryable<T> Find()
{
return _session.Query<T>();
}
}
note that in the constructor I use another nhibernate helper I created that wraps the session factory. this is where I have a dependency on nhibernate.
if I ever wanted to replace NH with another ORM, I would need to modify only the repository class (and the underlying supporting classes), you can see that NH does not leak outside the Repository class and no one that uses it are aware of the usage of NH.
I noticed that most people spoke of implementation/tech but no one mentioned the application or thrust of domain driven design . Well DDD is not necessarily something you can achieve by just adding in dapper/ef/enterprise library blocks. These can help, as can SOLID and things like cqs command/query separation but these are merely enablers there are more considerations and questions which need to be asked. Take a look at " domain driven design quickly" on infoq for a few more ideas.

Spring Autowiring by variable name

Below is my controller. My program generates an output, based on a form input. Across the project, there are multiple input forms, that generate the output object. So, the essential flow is the same. So I want a single multi-action controller that does all of that.
Challenges:
1. The service classes change. Although all services implement the same interface, and controller calls the same interface method.
2. The input objects change. Although the input objects do not have any methods other than setters, and getters. So I let them all implement an empty interface.
Questions:
How do I change the qualifier, based on the path. Can I use path variables?
Suppose the path has this value -> singleton. Then my corresponding bean names would be singletonService and singletonInput. I want to make a constant class that has stores this mapping information. So, can I call that from inside the qualifier, using some Spring Expression Language? Example, instead of Qualifier(variablePathName) -> Qualifier(getQualifierName['variablePathName']) Something like that?
Please also clarify the theory behind this. From what I understand, beans are created, autowired before the Request are mapped... Does this mean that what I'm trying to achieve here is simply not possible. In that case, would you suggest making Controller-service pairs for handling each request, with basically the same code? But I feel there must be some way to achieve what I'm trying...
Code:
#Cotroller
#RequestMapping(value="/generate/{path}")
public class TestController {
#Autowired
#Qualifier(......)
private IService service;
#Autowired
#Qualifier(......)
IUserInput userInput;
#RequestMapping(method = RequestMethod.POST)
//Some handler method
}
You're right in that the autowiring is all done once up front (point 3). You wouldn't be able to achieve what you want using fields annotated #Autowired and #Qualifier - as these fields would always reference the same bean instance.
You may be better to ask Spring for the particular service bean by name - based on the path variable. You could do it within a single controller instance. For example:
#Cotroller
#RequestMapping(value="/generate/{path}")
public class TestController {
#Autowired
private ApplicationContext applicationContext;
#RequestMapping(method = RequestMethod.POST)
public String someHandlerMethod(#PathVariable String path) {
IService service = (IService) applicationContext.getBean(path + "Service");
IUserInput userInput = (IUserInput) applicationContext.getBean(path + "UserInput");
// Logic using path specific IService and IUserInput
}
}

ASP.NET custom MembershipProvider and shared DbContexts

I have created a custom MembershipProvider in an MVC web appliocation. My GetUser function returns an instance of my own custom Employee class which inherits from the standard MembershipUser. This allows me to supply additional details for the each user such as various employee details.
public override MembershipUser GetUser(string username, bool userIsOnline)
{
return new ModelRepository().GetModels<Employee>().Where(e => e.UserName == username).FirstOrDefault();
}
The problem I'm having, the membership provider spawns a new instance of my repository class (which creates a new DbContext) to retrieve the Employee object. This Employee object is then passed to whatever request/controller action called the Membership api.
Employee currentUser = (Employee)Membership.GetUser();
That calling request will often want to create a new object in memory, lets say a new SicknessRecord and assign the user retrieved earlier to that record and then save it to the DB with its own model repository. You can probably see where this is going, the framework complains that I'm trying to save an object (the user) with a context that it wasn't initially retrieved with.
My current, rather hackish solution is to just use the ID of the user retrieved from the Membership.GetUser and go and re-retrieve the Employee object from my current model repository.
newSickness.Employee = this.modelRepository.GetModelById<Employee>(this.me.Id.Value);
I've tried detaching the Employee object but then it loses its lazy loaded properties and I have to remember to try and attach it again to my current repository/context.
I've also read it is good to have your custom membership provider share the same context that the current request would be using. Any ideas how to achieve this, how do I ensure the membership provider uses the same context as the one spawned when a user executes a controller action?
You can have one separate DbContext instance for each controller.
public class SomeController : Controller
{
private DbContext context = new DbContext();
private CustomMembershipProvider membershipProvider = new CutomMembershipProvider(this.context);
... Actions ....
}
As far as I know, one context per controller is good practice.
By the way, if you have several repositories try to use UnitOfWork with Repository pattern.

ASP.NET MVC Design Question - Where to put DB access code?

I've been playing around with ASP.NET MVC for the past few weeks. I've got a simple web application with a form which contains a number of drop down lists.
The items in the drop down lists are stored in a database, and I'm using LINQ to SQL to retrieve them.
My question is - where's the appropriate place to put this code? From what I've read so far, it seems that it's advisible to keep the Controller 'thin', but that's where I currently have this code as it needs to be executed when the page loads.
Where should I be putting DB access code etc.? I've included an excerpt from my controller below.
Thanks.
public ActionResult Index()
{
TranslationRequestModel trm = new TranslationRequestModel();
// Get the list of supported languages from the DB
var db = new TransDBDataContext();
IEnumerable<SelectListItem> languages = db.trans_SupportedLanguages
.Select(c => new SelectListItem
{
Value = Convert.ToString(c.ID),
Text = c.Name.ToString()
});
ViewData["SourceLanguages"] = languages;
ViewData["TargetLanguages"] = languages;
return View();
Your database access code should be in a repository. Example:
public interface ITranslationRepository
{
Translation GetTransaltion();
}
and the controller would use this repository:
public class TransaltionController : Controller
{
private readonly ITranslationRepository _repository;
public TransaltionController(ITranslationRepository repository)
{
_repository = repository;
}
public ActionResult Index()
{
// query the repository to fetch a model
Translation translation = _repository.GetTransaltion();
// use AutoMapper to map between the model and the view model
TranslationViewModel viewModel = Mapper.Map<Translation, TranslationViewModel>(model);
// pass the view model to the view
return View(viewModel);
}
}
So the basic idea is the following:
The controller queries a repository to fetch a model
The controller maps this model to a view model (AutoMapper is great for this job)
The controller passes the view model to the view
The view is strongly typed to the view model and uses it to edit/display
As far as the implementation of this repository is concerned feel free to use any data access technology you like (EF, NHibernate, Linq to XML, WCF calls to remote resources over the internet, ...)
There are the following advantages:
The controller logic is completely decoupled from the data access logic
Your controllers can be unit tested in isolation
Your models are not littered with properties that should belong to the UI layer (such as SelectListItem) and thus are reusable across other types of application than ASP.NET MVC.
The view model is a class which is specifically tailored to the needs of the view meaning that it will contain specific formatted properties and the view code will be extremely readable.
Your views are strongly typed => no more ViewData and ugly magic strings
Suggest that your data-access code should be contained in its own project/assembly. That is referenced by the UI tier (ASP.NET MVC application). That'll help achieve the goal of keeping your Controllers thin, and keep all the data access code out of your MVC UI project.
That typically leads to another question/discussion about domain entities: when mapping to the data store. Some architects like to have the entities in their own separate assembly. This encourages reuse in other applications. Some like to keep the entity model and data access code in the same project/assembly. This is totally up to you and your environment.
For an example, let's say it's a billing application; holding customers, invoices, etc.
Your implementation will be different, depending on your data access strategy (an ORM like LINQ To SQL, EF, nHibernate, SubSonic, or plain old ADO.NET, or reading from a flat file).
// Assembly: InvoicingDL
public class CustomerRepo
{
public IQueryable<Customer> ListCustomers()
{
return MyDatabase.Customers(); //however you'd get all your customers
}
//etc
}
// Assembly: InvoicingDL
public class InvoicingRepo
{
public IQueryable<Invoice> GetCustomerInvoices(int custID)
{
return MyDatabase.Invoices.Where(i=>i.CustomerID==custID);
}
//etc
}
Check out the Repository pattern
https://web.archive.org/web/20110503184234/http://blogs.hibernatingrhinos.com/nhibernate/archive/2008/10/08/the-repository-pattern.aspx
http://www.mindscapehq.com/blog/index.php/2008/05/12/using-the-unit-of-work-per-request-pattern-in-aspnet-mvc/
The idea is you abstract your data access in something called a repository that returns domain objects. Your controller can then use this repository to get the appropriate objects from the database and assign them to the model.

IRepository confusion on objects returned

I have some e-commerce code that I use often that uses Linq To SQL for saving orders to the database. I want to remove the tightly coupled Linq to SQL bit and pass in an IRepository instead but I am still a little confused on things.
Say I have a GetCustomer() method on my ICustomerRepository that returns a Customer object.
Do I need it to really return an ICustomer object that gets passed back from that method so if I switch from Linq To SQL to say SubSonic it's not a problem?
I believe I do, if that is the case is there a way in Linq To SQL to easily convert my Linq To SQL Customer object to my ICustomer object like SubSonics ExecuteSingle(Of ) method?
If you want your Customer class to be a plain object with no attachment to LINQ, then you will most likely need to write a mapper method to convert your LINQ-based Customer object to your plain Customer domain object. LINQ to SQL does not have such functionality built-in.
I have begun to wrap my mapping methods in an extension method for readability, and it really helps to keep the Repository code simple. For instance, an example CustomerRepository method my look like:
public Customer GetById(int id)
{
return dataContext.LINQCustomers.Where(c => c.Id == id)
.Single()
.ToDomainObject();
}
and the ToDomainObject() method is defined in an extension method like:
public static class ObjectMapper
{
public static Customer ToDomainObject(this Customer linqObject)
{
var domainObject = null
if (linqObject != null)
{
domainObject = new Customer
{
Id = linqObject.Id,
FirstName = linqObject.FirstName,
LastName = linqObject.LastName
}
}
return domainObject;
}
}
or something similar. You can do the same to convert your domain object back to a LINQ object to pass back into your repository for persistence.
You can have it return a Customer as long as Customer is a plain old .NET object, and not some db-generated entity. Your Customer domain object should have no knowledge about how (or if) it might be persisted to a database, and this is what should be returned from your repository. In your repository you might have some mapping code - this is quite common - that maps from [however you get the data back from its storage location] to your domain object. If you're using Linq-to-sql then this mapping would be from the Linq-To-Sql generated Customer table (and perhaps other tables - your Customer domain object likely won't map 1:1 to a particular table in the database) to your Customer domain object, which would live in a different namespace (and most likely, assembly).
There is no need to make it an ICustomer at all. A repository acts in a way as to make it look as though your persistent instances are in memory.
public interface ICustomerRepository
{
Customer GetByID(int id);
IEnumerable<Customer> GetByName(string name);
Customer GetByVatCode(string vatCode);
}
Some people would additionally include methods such as
void Add(Customer newCustomer);
void Delete(Customer deleted);
void Update(Customer modified);
The latter method implementations would most likely just update a unit of work.
The concept though is that these are just common ways of asking for Customer instances, the repository acts as a way of asking for them without defining how to ask for them.

Resources