i have an asp.net mvc based website, consist of three layers:
presentation layer (mvc website)
Domain layer (class library )
Data layer (class library)
and here is my code
presentation layer:
public ActionResult MyAction(int categoryId = 1)
{
var products = service.GetProductsByCategory(categoryId);
return View(products );
}
Domain Layer:
public List<MyProduct> GetProductsByCategory(int categoryId)
{
/* some code here */
return myProductDao.GetProductsByCategory(categoryId);
}
Data Layer:
public List<MyProduct> GetProductsByCategory(int categoryId)
{
/* check if data available in cache to avoid pulling database */
using (var context = new myDbEntities())
{
var myproducts = context.ProductEntities.Where(p => p.CategoryId == categoryId);
return Mapper.Map<List<ProductEntity>, List<Product>>(products);
}
}
We supposed that product table change only one time a day, and i want add a caching layer to avoid pulling database for a specific time.
problem:
i'm usually using HttpContext.Cache.Insert() in controller for caching, but now i'm planning to add caching to Data layer which it is a class library and there is no HttpContext. how usually caching done in datalayer
There are many ways to solve this. What I would do is abstract away the how to cache with an interface and inject however you want to cache into the data layer (including using HttpContext.Cache.Insert).
MyProject.Cache
public ICache
{
void Insert (string key, object value)
}
MyProject.Web
internal WebCache : ICache
{
public void Insert(string key, object value)
{
HttpContext.Cache.Insert(key, value);
}
}
public Controller
{
private service = new service(new WebCache);
}
MyProject.Domain
public Service
{
private readonly ICache _cache;
private readonly MyProductDao _myProductDao;
public Service(ICache cache;)
{
_cache = cache;
_myProductDao = new MyProductDao(_cache);
}
public List<MyProduct> GetProductsByCategory(int categoryId)
{
/* some code here */
return _myProductDao.GetProductsByCategory(categoryId);
}
}
MyProject.Data (if you just want to cache in the data layer)
public MyProductDao
{
private readonly ICache _cache;
public MyProductDao(ICache cache)
{
_cache = cache;
}
public List<MyProduct> GetProductsByCategory(int categoryId)
{
/* check if data available in cache to avoid pulling database */
_cache.DoWhatever()....
using (var context = new myDbEntities())
{
var myproducts = context.ProductEntities.Where(p => p.CategoryId == categoryId);
return Mapper.Map<List<ProductEntity>, List<Product>>(products);
}
}
Extend ICache as needed and implement it on your internal WebCache.
how usually caching done in datalayer
I don't think it should be done in the data layer.
Adding caching to the data layer seems to me like a violation of the Single Responsibility Principle. Your data layer should only be responsible for one thing - getting data from the persistent store (i.e. the database).
At some place in your code, you will need to do this workflow (or some variant of it):
Check the cache for item X.
If it is found, get the item from the cache.
If it is not found, get the item from the persistent store.
Return the item.
In my opinion, a component that is separate from the data layer should do this workflow.
Look at it this way: once you put a cache in front of your database persistence layer, you're not just getting data from the DB any more. You're getting data from this new component, and the component decides where to get the record from (cache vs. DB).
Related
I am working on a project(asp.net mvc-5 with jQuery) in which whole validation is happening in front-end and we are executing api's using $.ajax call, now as there are no validations on api level or not even in stored procedures of sql server, a user can easily access the the api's with wrong values, so We decided to add a logic layer in our application
so before that our structure looks like the below
jQuery -> Api layer -> Db layer
now I want to add a layer between Api layer and Db layer which will be called as Logic layer
the new structure will look like below
jQuery -> Api layer -> Logic layer -> Db layer
Note:
all the layers are different projects in same solution
Logic layer and Db layer is a class library file
Db layer is divided into 2 sub catogories (interface and class)
So we have 4 class library 1 api and 1 front end
interfaces are inherited in the class files
the class library is like below
db.Interface(class library project)
db.Class(class library project)
Logic.Interface(class library project)
Logic.Class(class library project)
We have already added dependencies for db layer the code for which looks like below,
Set of code In global.asax.cs
//Helps to find all the classes of Dblayer
string dbName = ConfigurationManager.AppSettings["DB"];
string dbDAL = Path.Combine(Server.MapPath("./DAL"), "DocPro.DMS.BusinessLayer." + dbName + ".dll");
AssemblyName an = AssemblyName.GetAssemblyName(dbDAL);
Assembly assembly = Assembly.Load(an);
Type[] assemblyTypes = assembly.GetTypes();
DALFinder.Initialize(assemblyTypes);
class file in api project called DalFinder
public static class DALFinder
{
private static List<Type> TypeList { get; set; } = new List<Type>();
public static void Initialize(Type[] typelist)
{
TypeList.Clear();
TypeList = typelist.ToList<Type>();
}
public static object GetInstance(Type plugin)
{
foreach (Type type in TypeList)
{
if (type.IsInterface || type.IsAbstract)
{
continue;
}
else
{
if (type.GetInterface(plugin.FullName) != null)
{
return Activator.CreateInstance(type, new object[] { Program.GetConnectionString() });
}
}
}
return null;
}
}
and while executing a particular function I needed to do the below in my Api layer
BusinessLayer.IAdmin.IFolderRole a = (BusinessLayer.IAdmin.IFolderRole)DALFinder.GetInstance(typeof(BusinessLayer.IAdmin.IFolderRole));
response = a.SaveFolderRole(item);
now for my current scenario I want to call db layer from my logic layer but since it is a class library file I failed to understand what should I do, for now I did something like below
public class DocTemplateController : ApiController
{
private LogicLayer.IAdmin.IDocTemplate _LogicLayer;
private BusinessLayer.IAdmin.IDocTemplate _Businesslayer;
public DocTemplateController()
{
_LogicLayer = (LogicLayer.IAdmin.IDocTemplate)BusinessLayerFinder.GetInstance(typeof(LogicLayer.IAdmin.IDocTemplate));
_Businesslayer = (BusinessLayer.IAdmin.IDocTemplate)DALFinder.GetInstance(typeof(BusinessLayer.IAdmin.IDocTemplate));
}
[HttpPost]
[Route("api/Admin/DocTemplate/GetDocTemplates")]
[Authorize]
[Filters.AuthorizeLoginApi()]
public async Task<GetTemplatesList> GetDocTemplates(DocTemplate request)
{
var response = new GetTemplatesList() { LogicLayerValidation = false };
try
{
response = _LogicLayer.GetDocTemplates(request);
if (response.LogicLayerValidation != false)
response.GetTemplates = await _Businesslayer.GetDocTemplates(request.TemplateName, request.AccountId);
}
catch (Exception ex)
{
Utils.Logger.Instance.LogException(ex);
response.LogicLayerValidation = false;
response.LogicLayerMessage = ex.Message;
}
return response;
}
}
and as I understand (I might be wrong) that this is a bad way of coding, I want to follow the structure of
jQuery -> Api layer -> Logic layer -> Db layer
how can I do this?
EDIT:
After I put bounty on the question I received lots of answers, but I
think so I needs to edit this question and provide more details, (all
the answers are good and can be very helpful for many but
unfortunately I am failed to get what I wanted)
this is how my controller looks like,
[RateLimitApi]
public class UserController : ApiController
{
private readonly LogicLayer.IAdmin.IUsers _LogicLayer;//Logic layer
private readonly LogicLayer.IGlobalValidation _CommonLogicLayer; //common logic layer
private readonly BusinessLayer.IAdmin.IUsers _Businesslayer;// business layer
private readonly BusinessLayer.IAccess.IUser _IAccessBusinesslayer;//business layer which is being used in another api
private BusinessEntities.Response.LogicLayerValidationResult _Llv; //entity for logiclayer
private SPResponse _Sp; //response entity for add/edit
private readonly ErrorLogger _Er; error log class
private readonly BusinessEntities.Response.Admin.GetUsersList _UserList; //user list
private readonly BusinessEntities.Response.Admin.GetUsersSingle _UserSingle; //single user
public UserController()
{
_LogicLayer = (LogicLayer.IAdmin.IUsers)BusinessLayerFinder.GetInstance(typeof(LogicLayer.IAdmin.IUsers));
_Businesslayer = (BusinessLayer.IAdmin.IUsers)DALFinder.GetInstance(typeof(BusinessLayer.IAdmin.IUsers));
_IAccessBusinesslayer = (BusinessLayer.IAccess.IUser)DALFinder.GetInstance(typeof(BusinessLayer.IAccess.IUser));
_CommonLogicLayer = (LogicLayer.IGlobalValidation)BusinessLayerFinder.GetInstance(typeof(LogicLayer.IGlobalValidation));
_Llv = new BusinessEntities.Response.LogicLayerValidationResult() { LogicLayerValidation = false };
_Sp = new SPResponse();
_Er = new ErrorLogger();
_UserList = new BusinessEntities.Response.Admin.GetUsersList();
_UserSingle = new BusinessEntities.Response.Admin.GetUsersSingle();
}
// GET: Admin/Users
[HttpPost]
[Authorize]
[ActionName("GetList")]
[Filters.AuthorizeLoginApi()]
public async Task<BusinessEntities.Response.Admin.GetUsersList> GetList(DocPro.DMS.BusinessEntities.Request.Admin.UsersRequest request)
{
try
{
// had to call logic layer and then call the business layer like below
_Llv = _LogicLayer.GetList(request);
if (_Llv.LogicLayerValidation)
{
_UserList.GetUsers = await _Businesslayer.GetList(request.LoginText, request.Name, request.Email, request.UserTypeId, request.IsActive, Convert.ToInt32(request.LoggedInUserId));
}
}
catch (Exception ex)
{
_Llv = _Er.LogExceptionWithLogicLayerValidations(ex, _Llv);
}
_UserList.LogicLayerValidation = _Llv;
return _UserList;
}
}
how can I do this?
is quite a general question (which is frown upon in this community).
I don't see any issue with the structure:
jQuery -> Api layer -> Logic layer -> Db layer
It is very common structure: frontend -> api-> business (logic) layer-> db
If it is a new project, I might recommend to do it with .net core and use the microsoft dependency injections or maybe use Autofac, since the topic is complex. If you really want to do it, then you can also browse their (ms or autofuc) code on github to familiarize yourself on the topic.
you should add a reference to your databaselayer project in your logic layer project. Then you can inject the db layer class in your logic layer class using dependency injection.
Then you can just call the db layer from the logic layer after you are done validating.
Why reinvent the wheel?
what you are asking for is already implemented in AspNet Boilerplate
More on this here
I would like to improve my .NET project by adding another layer when accessing the database. This is my code:
namespace Company.Models
{
public static class AgencyBean
{
[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public static String createGUID(string name)
{
DataAccess dataAccess = new DataAccess();
bool exists = dataAccess.checkIfExists(Id);
if(exist)
{
dataAccess.delete(Id);
}
retur "ok";
}
}
}
I placed DataAccess class in a separate folder called "Helpers" and it contains most of my queries:
public class DataAccess
{
public bool checkIfExists(String Id)
{
try
{
SqlConnection cnn = new SqlConnection(dataConnection);
cnn.Open();
SqlCommand check_Id = new SqlCommand("SELECT COUNT(*) FROM TABLE_GUID WHERE ([USER_ID] = #Id)", cnn);
check_Id.Parameters.AddWithValue("#Id", Id);
int UserExist = (int)check_Id.ExecuteScalar();
if (UserExist > 0)
{
return true;
}
else
{
return false;
}
}
catch (SqlException ex)
{
Debug.WriteLine("SQL Exception " + ex);
DisplaySqlErrors(ex);
throw ex;
}
}
}
public class AgentBeanController : Controller
{
// GET: AgentBean
public ActionResult Index(string name)
{
return View();
}
[AllowAnonymous]
[WebMethod]
public string AgentURL() //here we create Agent URL and return it to the view
{
string var = Models.AgentBean.createGUID("TODO");
return var;
}
}
I'm accessing the database pretty much in very direct way. How would it be with a better technique, so this access can be more secure, like accessing thru a service layer?
I'm connecting to a existing sql database in some server and working with MVC architecture in my project.
So here is what I have done in the past.
First, that is your "models" namespace... models should never have database connectivity. Instead you have a seperate class, such as a controller, that hydrates some model.
Second, I've had a "service" class, which hooks up to a "repository" class. The repository class implements an interface to identify the exact "type" of database you're using.. but if that's not a part of your requirements you probably don't need to go that far.
Third, look up dependency injection (aka, DI). There are several frameworks out there. Personally I've used Autofac, but others exist as well to get the job done easier.
Fourth, on your your "controllers", "services" and "respository" classes, implement dependency injection, as well as any interfaces as needed to form a contract.
Fifth, I would use an actual controller namespace and not be working out of your models namespace to be pushing http calls band and forth.... Instead, create an action in your controller class, and instantiate an instance of your "agencyBean", hydrate it with data, and return that model out to your view.
Basically, in a scenario like this you're trying to keep each component doing what it is designated to do... breaking down responsibilities into smaller pieces and focusing on that. Your controller should just "fetch" your model and maybe do some transformations on it as needed or any other business-type logic.
Your service should handle the communication between your controller and your database layer.
Your data access layer (ie, in this case, some "repository" class...) would do all of those new data connections and/or setting up calls to stored procedures or queries.
Doing things this way has a lot of benefit. Some of the big ones are maintainability, readability, code re-use. Sure it makes your project a bit more complicated in terms of files sitting wherever... but that can be a good thing. It's so much better than slamming everything into one single class and have it do everything :)
But, just FYI, this is from an implementation I've done in the past... I'm sure there are better ways but this setup worked quite well for my team and I.
Here is a small example using some of your code you posted. I DID NOT check this for typos and it wouldn't compile, but should help give a general idea of what I'm talking about....
namespace Company.Models
{
public class AgencyBean
{
public AgencyName{get;set;}
public AgencyId{get;set;}
// other properties...
}
}
namespace Company.Controllers
{
public class MyController : Controller
{
private readonly IMyService myService;
public MyController(IMyService myService) // <-- this is your dependency injection here...
{
this.myService = myService;
}
[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public static String createGUID(string name)
{
var model = new AgencyBean();
model.AgencyId = 1;
model = myService.getAgency(agencyBean);
return model;
}
}
}
namespace Company.Services
{
public class MyService
{
private readonly IMyRepository myRepository;
public MyService(IMyRepository myRepository) // <-- this is your dependency injection here...
{
this.myRepository = myRepository;
}
public AgencyBean getAgency(AgencyBean model){
var dataTable = myRepository.getAgencyData(model.AgencyId);
// fill other properties of your model you have...
// ...
// ...
return model;
}
}
}
namespace Company.Repositories
{
public class MyRepository : IDatabaseCommon // <-- some interface you would use to ensure that all repo type objects get connection strings or run other necessary database-like setup methods...
{
private readonly String connectionString{get;set;}
public MyRepository()
{
this.connectionString = //get your connection string from web.config or somewhere else...;
}
public DataTable getAgencyData(int id){
var dataTable = new DataTable();
// perform data access and fill up a data table
return dataTable;
}
}
}
Recently i've working on an ASP.NET MVC5 project, i dived right in and wrote all my logic right in the action method and after doing this for a few controllers i've noticed that i have been duplicating certain business rules and could do with being lifted out and shared between controllers.
From what i've read, the m in asp.net mvc is a layer consisting of entities, viewmodels and services, the latter holding all your shared business logic
now i'm trying to keep things as simple as possible, i don't want to wrap entity framework in some UoW/Repo and use it as-is, it is very unlikely that i'll stop using entity framework in this applications lifetime and i'm not doing unit tests and i'm not that bothered about tight coupling, so i don't feel i need an IoC container, but all the tutorials i've read seems to use either an IoC container or wraps dbcontext/ef in a UoW/Repo.
I've read that there should only be a single instance (which in the tutorials i've seen is managed via an IoC container) of DbContext per httprequest, would this be achieved by instantiating it in the controllers constructor and then passing that reference to any services needed in the controller and then disposing it at the end of the request? is this the correct way of managing dbcontext?
Controller example:
public class SupplierController : Controller
{
private Meerkat3Context context;
private SupplierService supplierService;
private ratingService SupplierRatingService;
public SupplierController()
{
// instantiate the dbcontext
this.context = new Meerkat3Context();
// pass dbcontext into the constructors of my services
this.supplierService = New SupplierService(context);
this.ratingService = New SupplierRatingService(context);
}
public ActionResult Index(Guid id)
{
var supplier = supplierService.getSupplier(id);
// construct viewmodel
return new SupplierIndexViewModel()
{
SupplierId = supplier.Id,
SupplierName = supplier.Name,
SupplierRating = ratingService.getHighestRating(supplier.Id),
NearbySuppliers = supplierService.getNearbySuppliers(supplier.Id),
// etc
};
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
context.Dispose();
}
base.Dispose(disposing);
}
}
Service examples:
public class SupplierService
{
private Meerkat3Context context;
public SupplierService(Meerkat3Context context)
{
this.context = context;
}
public Supplier getSupplier(Guid id)
{
return context.Where(x => x.SupplierId == id)
.FirstOrDefault()
.Select(x => new Supplier()
{
Id = x.Id,
Name = x.Name
// etc
});
}
public Supplier getNearbySuppliers(Guid id)
{
return context.Suppliers.Where(x => context.SupplierAddresses
.Where(y => y.AddressTypeId == AddressTypes.Location)
.Select(z => z.Address.TownCity)
.Contains(x.SupplierAddresses
.Where(y => y.AddressTypeId == AddressTypes.Location)
.FirstOrDefault()
.Address.TownCity)
);
}
}
public class SupplierRatingService
{
private Meerkat3Context context;
public RatingService(Meerkat3Context context)
{
this.context = context;
}
public SupplierRating getHighestRating(Guid id)
{
return context.SupplierRating
.Where(x => x.SupplierId == id)
.OrderBy(x => x.RatingValue)
.FirstOrDefault()
}
}
If you're trying to strip out the repeated code, this should be fairly simple. In VS you can highlight a section of code and use the hotkeys Ctrl+R,Ctrl+M for refactor, or you can do so by using the context menu highlight code section > right-click > Refactor > Extract Method.
If the usage of the repeated code can be replicated for all entities, you can create a static class that houses this common functionality.
public sealed class Utlities
{
public static CommonA() { }
public static CommonB() { }
... etc...
}
And you can call them easily using Utilities.CommonA(). Another way to reduce redundancy is to use ViewModels. Basically create a copy of the entity you want to use as a ViewModel with additional properties required for the View. If the models have data in common, create a base class to inherit those commonalities from.
public class BaseViewModel
{
public Type Prop {get; set;}
public Type Prop2 {get; set;}
...etc...
}
public class SpecificViewModel : BaseViewModel
{
SpecificViewModel(Type Prop, Type Prop2) : base(Prop, Prop2, ...etc...) { }
public Type specificProp {get; set;}
...etc...
}
If I understood your question correctly that is.
If what you want is simply moving out reusable logic then your approach is good enough. But please bear in mind that:
it isn't testable (you can't isolate your dependencies and
You're still duplicating the logic, even if it's simply an object construction logic (e.g., in every controller where you need SupplierService you'll have to instantiate Meerkat3Context as well). That can get quite tedious (and that's where DI comes in handy)
With an IoC container your controller would look like.
public class SupplierController : Controller
{
//the controller doesn't need to create the db context now
//this concern is handled now by the IoC container
private SupplierService supplierService;
private RatingService SupplierRatingService;
public SupplierController(SupplierService supplierService, RatingService ratingService)
{
// we don't have to pass the db context now to services, since we retrieve the services from the IoC container. The IoC container auto-wires the services
this.supplierService = supplierService;
this.ratingService = ratingService;
}
public ActionResult Index(Guid id)
{
var supplier = supplierService.getSupplier(id);
// construct viewmodel
return new SupplierIndexViewModel()
{
SupplierId = supplier.Id,
SupplierName = supplier.Name,
SupplierRating = ratingService.getHighestRating(supplier.Id),
NearbySuppliers = supplierService.getNearbySuppliers(supplier.Id),
// etc
};
}
// the controller doesn't need a dispose method since the IoC container will dispose the dbcontext for us
}
You don't have to follow the Dependency Inversion Principle to use an IoC container, but you can count on a IoC container to create and to manage the lifetime of your services objects.
You configure the IoC container to create a single instance of a dbcontext per a web request. The good part is this is configurable and, if you later decide is better to have a different dbcontext instance per service, then you just change this in a single place and not in every controller and every action method where you use the new keyword.
First a little background: I have a solution with the following 3 projects in it:
MVC Project (User facing website)
API Project (business logic project)
Data Access Project (project where NHibernate lives)
I have the Fluent mappings in the DA layer, and (for now) I build the Hibernate SessionFactory in the GLobal.asax of the MVC site. This is not ideal as I want to have NHibernate completely contained in the DA layer and have the MVC app only communicate with the API layer. Also, I want to build the SessionFactory only once as it is an expensive operation.
To make things more complicated I have an inheritance structure like so:
User object in API layer inherits from
User data object in DA layer inherits from
Data object in DA layer.
Data object is responsible for saving the object to the database as the saving function is the same across all objects and I do not want to repeat code. The problem I am having is how do I save the User object to the database from inside the Data object class while using a SessionFactory that I instantiated when the user logged into the website and can persist through out their session.
If anything is not explained clearly please let me know.
One way to do that would be using the DI pattern, with e.g. Unity.
Implement your data object having a constructor which takes for example an IRepository interface. The implementation of this interface handles the nHibernate session factory...
Your data object could also be generic where T is one for example User data object. Then you implement a methods in data object to e.g. save, update, delete T with the injected IRepository
pseudo code for a data object
public interface IEntity
{
}
public interface IRepository
{
ISession Session { get; }
}
public class DataObjectBase<T> where T : IEntity
{
private IRepository Repository { get; set; }
public DataObjectBase(IRepository repository)
{
this.Repository = repository;
}
public T Get(int id)
{
return Repository.Session.Get<T>(id);
}
public void Save(T value)
{
Repository.Session.Save(value);
}
public void Update(T value)
{
Repository.Session.Update(value);
}
public void Delete(T value)
{
Repository.Session.Delete(value);
}
public IQueryable<T> Query()
{
return Repository.Session.Query<T>();
}
}
Implementation of your specific data object
public class ADataObject : IEntity
{
public int Id { get; set; }
// [...]
}
Implementation of your data context for the data object
public class ADataObjectContext : DataObjectBase<ADataObject>
{
public ADataObjectContext(IRepository repository)
: base(repository)
{
}
}
A simple example test using Unity
public class Test
{
public void Run()
{
IUnityContainer myContainer = new UnityContainer();
myContainer.RegisterType<IRepository, NHibernateRepository>();
var ctx = myContainer.Resolve<ADataObjectContext>();
var obj = ctx.Query().Where(p => p.Id == 2);
}
}
Of cause you would have to implement the NHibernateRespository to do whatever you want it to.
The UnityContainer initialization should be done within your global.asax within the MVC project. You can also configure Unity via web.config.
The NHibernateRespository should actually be a singleton. This can either be implemented by you, or you simply use the Unity functionality to instantiate your type as singleton. The new ContainerControlledLifetimeManager() does exactly that.
Instead of exposing the session as a property you can of cause expose a method which opens a new session. Or you implement a Begin and End unit of work, which is common practice in web environments...
Other links for a normal repository pattern, and unit of work, unity... or simply search on Google for nhibernate repository pattern
http://slynetblog.blogspot.de/2011/11/in-spite-of-common-now-approach-of.html
http://blog.bobcravens.com/2010/07/using-nhibernate-in-asp-net-mvc/
http://msdn.microsoft.com/en-us/library/dd203101.aspx
You can use this options:
Using AOP: when a function is called in API layer, AOP creates a session and passes the value parameters in methods or constructors to DA layer.
From MVC project to DA layer, it passes a session to DA layer with parameters in method o constructors, through all the layers.
Thinks the session is always associated with the interface layer.
I am using the Entity framework for the first time, and would like to know if I am using in the best practice.
I have created a separate class in my business logic which will handle the entity context. the problem I have, is in all the videos I have seen they usually wrap the context in a using statement to make sure its closed, but obviously I can't do this in my business logic as the context will be closed before I can actually use it?
So is this ok what I'm doing? A couple of examples:
public IEnumerable<Article> GetLatestArticles(bool Authorised)
{
var ctx = new ArticleNetEntities();
return ctx.Articles.Where(x => x.IsApproved == Authorised).OrderBy(x => x.ArticleDate);
}
public IEnumerable<Article> GetArticlesByMember(int MemberId, bool Authorised)
{
var ctx = new ArticleNetEntities();
return ctx.Articles.Where(x => x.MemberID == MemberId && x.IsApproved == Authorised).OrderBy(x => x.ArticleDate);
}
I just want to make sure I'm not building something that's going to die when a lot of people use it?
It really depends on how to want to expose your repository/data store.
Not sure what you mean by "the context will be closed, therefore i cannot do business logic". Do your business logic inside the using statement. Or if your business logic is in a different class, then let's continue. :)
Some people return concrete collections from their Repository, in which case you can wrap the context in the using statement:
public class ArticleRepository
{
public List<Article> GetArticles()
{
List<Article> articles = null;
using (var db = new ArticleNetEntities())
{
articles = db.Articles.Where(something).Take(some).ToList();
}
}
}
Advantage of that is satisfying the good practice with connections - open as late as you can, and close as early as you can.
You can encapsulate all your business logic inside the using statement.
The disadvantages - your Repository becomes aware of business-logic, which i personally do not like, and you end up with a different method for each particular scenario.
The second option - new up a context as part of the Repository, and make it implement IDisposable.
public class ArticleRepository : IDisposable
{
ArticleNetEntities db;
public ArticleRepository()
{
db = new ArticleNetEntities();
}
public List<Article> GetArticles()
{
List<Article> articles = null;
db.Articles.Where(something).Take(some).ToList();
}
public void Dispose()
{
db.Dispose();
}
}
And then:
using (var repository = new ArticleRepository())
{
var articles = repository.GetArticles();
}
Or the third-option (my favourite), use dependency injection. Decouple all the context-work from your Repository, and let the DI container handle disposal of resources:
public class ArticleRepository
{
private IObjectContext _ctx;
public ArticleRepository(IObjectContext ctx)
{
_ctx = ctx;
}
public IQueryable<Article> Find()
{
return _ctx.Articles;
}
}
Your chosen DI container will inject the concrete ObjectContext into the instantiation of the Repository, with a configured lifetime (Singleton, HttpContext, ThreadLocal, etc), and dispose of it based on that configuration.
I have it setup so each HTTP Request gets given a new Context. When the Request is finished, my DI container will automatically dispose of the context.
I also use the Unit of Work pattern here to allow multiple Repositories to work with one Object Context.
You may have also noticed I prefer to return IQueryable from my Repository (as opposed to a concrete List). Much more powerful (yet risky, if you don't understand the implications). My service layer performs the business logic on the IQueryable and then returns the concrete collection to the UI.
That is my far the most powerful option, as it allows a simple as heck Repository, the Unit Of Work manages the context, the Service Layer manages the Business Logic, and the DI container handles the lifetime/disposal of resources/objects.
Let me know if you want more info on that - as there is quite a lot to it, even more than this surprisingly long answer. :)
I would have the ctx as a private variable within each class, then create a new instance of this each time and then dispose when finished.
public class ArticleService
{
private ArticleEntities _ctx;
public ArticleService()
{
_ctx = new ArticleEntities();
}
public IEnumerable<Article> GetLatestArticles(bool Authorised)
{
return _ctx.Articles.Where(x => x.IsApproved == Authorised).OrderBy(x => x.ArticleDate);
}
public IEnumerable<Article> GetArticlesByMember(int MemberId, bool Authorised)
{
return _ctx.Articles.Where(x => x.MemberID == MemberId && x.IsApproved == Authorised).OrderBy(x => x.ArticleDate);
}
public void Dispose()
{
_ctx.Dispose();
_ctx = null;
}
}
Then when calling this.
ArticleService articleService = new ArticleService();
IEnumerable<Article> article = articleService.GetLatestArticles(true);
articleService.Dispose(); // killing the connection
This way you can also add/update other objects within the same context and call a save method which saves any changes to the db through the Entity.
In my experience this code is not good, because you lose the capacity to navigate relationships through navigation properties.
public List<Articles> getArticles( ){
using (var db = new ArticleNetEntities())
{
articles = db.Articles.Where(something).ToList();
}
}
Using this approach you can't use the following code because a.Members is always null( db context is close and cant get data automatically).
var articles = Data.getArticles();
foreach( var a in articles ) {
if( a.Members.any(p=>p.Name=="miki") ) {
...
}
else {
...
}
}
}
Using only a global db context is a bad idea because you must use a delete changes function
in a point of your application yo do this but don't save changes and close the window
var article= globalcontext.getArticleByID(10);
article.Approved=true;
then in another point of application you make some operation and save
//..... something
globalcontext.saveChanges();
in this case previous article approved property is set to modified by entity framework. When you save, approved is set true!!!
Best approach for me is use 1 context per class
You can pass context to another external method if you need
class EditArticle {
private DbEntities de;
private currentAricle;
public EditArticle() {
de = new DbEntities; //inizialize on new istance
}
loadArticleToEdit(Articele a){
// a is from another context
currentArticle= de.Article.Single(p=>p.IdArticle==a.IdArticle){
}
private saveChanges(){
...
pe.saveChanges();
}
}
What you can also do is store your context at a higher level.
E.g., you can have a static class storing the current context:
class ContextManager
{
[ThreadStatic]
public static ArticleEntities CurrentContext;
}
Then, somewhere outside you do something like this:
using (ContextManager.CurrentContext = new ArticleEntities())
{
IEnumerable<Article> article = articleService.GetLatestArticles(true);
}
Then, inside the GetLastestArticles, you just use the same ContextManager.CurrentContext.
Of course, this is just the basic idea. You can make this a lot more workable by using service providers, IoC and such.
You can start preparing Entity Framework from data access layer by creating a generic repository class for all required Entity Framework functions. Then you can used it in Business layer (Encapsulated)
Here are the best practices that I have used for Entity Framework in data, business, and UI layers
Techniques used for this practice:
Applying SOLID architecture principles
Using Repository design pattern
Only one class to go (and you will find it ready)