On how I access my DataContext (and whether it's wrong) - c#

I use the following, static class to access the data context in my application
public static class DataContext
{
internal const string _contextDataKey = "dataContext";
/// <summary>
/// Returns a unique data context that lives for the duration of the request, which can be from ASP.NET or a WCF service
/// </summary>
/// <returns>The entity data model context for the current request</returns>
public static EntityDataModelContext GetDataContext()
{
IPersistanceContainer state;
if (HttpContext.Current != null)
{
state = new AspNetPersistanceContainer();
}
else if (OperationContext.Current != null)
{
state = new WcfPersistanceContainer();
}
else
{
state = new StaticPersistanceContainer(); // this container is thread-unsafe.
}
EntityDataModelContext edm = state.Get<EntityDataModelContext>(_contextDataKey);
if (edm == null)
{
edm = new EntityDataModelContext();
state.Store(_contextDataKey, edm);
}
return edm;
}
}
Forget about the other containers, which are for WCF and Console application simple-tests respectively, here's the ASP.NET container:
internal class AspNetPersistanceContainer : IPersistanceContainer
{
public T Get<T>(string key) where T : class
{
if (HttpContext.Current.Items.Contains(key))
return (T)HttpContext.Current.Items[key];
return null;
}
public void Store(string key, object value)
{
HttpContext.Current.Items[key] = value;
}
}
When I need to access the context I just invoke DataContext.GetDataContext() and do my DB-accessing, I never add any using statements.
If I add a using statement, the context is good for one use, and the next time I try to use it, it's disposed of. Raising an exception.
If I don't, like right now, it makes me kind of unhappy, I feel like it's not the right thing to do either, not disposing of it.
So I was wondering what would be the correct thing to do here.
Is this design flawed, and should I abandon it altogether?
Should I just figure out a way to re-create the context whenever it's disposed of?
Should I just leave the design as is, and that's fine?
Maybe the design is "fine enough", are there any books that you'd recommend I read on the subject? I feel like my skills on back-end architecture are rather on the lacking side.

In an asp.net application one solution can be like this :
Create your context when a request begins
Dispose it when the request ends
Here's an article that discuss this approach (for NHibernate session management but it's almost the same for EF )

Related

Proper use of Singleton in DAL and BO layer?

I'm tasked with implementing a Business Object / Data Access Layer for a project and have to expect thousands of users concurrently.
I've always used singletons to manage the DAL but I never game too much thought about how it would behave with so many multiple users at the same time, so I'd like to ask the proper use for it.
I have:
public class UserDAL
{
private static UserDAL _userDAL = null;
//Private constructor
private UserDAL() { }
public static UserDAL GetInstance()
{
if(_userDAL == null)
{ _userDAL = new UserDAL(); }
return _userDAL;
}
//Example of a method
public User GetUsers()
{
IDataReader dataReader = ConnectionFactory.GetConnection().ExecuteSomeQuery("queryHere");
}
}
For my Connection Factory I don't think it's a problem, although I did read that it's best to leave the connection pooling to ADO.NET itself:
public sealed class ConnectionFactory
{
private static string _connectionString = ConfigurationManager.ConnectionStrings["ConnectionName"].ConnectionString;
//My connection interface
private static IConnection _connection = null;
public static IConnection GetConnection()
{
if(_connection == null)
{
//some checks to determine the type
_connection = new SQLConnection(_connectionString);
}
return _connection;
}
}
I'm also using the singleton pattern in the BO, although I don't think it's necessary:
public class UserBO
{
private static UserBO _userBO = null;
private static UserDAL _userDAL = null;
private UserBO() { }
public static UserBO GetInstance()
{
if(_userBO == null)
{
_userBO = new UserBO();
_userDAL = UserDAL.GetInstance();
}
return _userDAL;
}
//Example of a method
public User GetUser()
{
//Rules
return _userDAL.GetUsers();
//return UserDAL.GetInstance().GetUsers(); //or this
}
}
I'm doing it like this just so I can call in the UI/Presentation layer:
User someUser = UserBO.GetInstance().GetUser(1);
This worked for me for the applications I've made so far, but I'm guessing it's because there wasn't too many users simultaneously.
I'm worried about what would happen in the UserDAL instance when a second user requests something but there's already a 1st user doing some heavy operation in it.
Should I drop this pattern in the BO/DAL layer and leave it only in the ConnectionFactory? Are there any issues which I should expect if I use this?
I would definitely drop it altogether, especially for the Connection: the connectionFactory could be static, but return a new connection each time it is asked: ADO.NET is very good at managing connection pooling and you just need to get out of it's way.
In anything which has changeable state keep away from singletons. This includes ADO.NET connections, and your actual Business Objects. Having one user mutate the state of an object that is being used by another user can lead to all sorts of strange bugs: in a web site, you basically have a massively multithreaded application and changeable singletons are very bad news!
You do need to come up with some sort of locking strategy, though, for when two or more users change copies of the same business object. A valid strategy includes saying 'Actually, this isn't going to be a problem so I'll ignore it' - but only if you have thought about it. The two basic strategies are Optimistic and Pessimistic Locking.
Optimistic Locking means that you optimistically think mostly the users won't change the same things (for whatever reason) and so you don't put Database locks on read data. This is the only possibility on a Web Site
Pessimistic locking says all possibly changed data will, when read, have DB Locks applied until the user is finished with it. This means keeping a Transaction open, and it's not practical for a Web Site.
Optimistic Locking can be implemented by creating Update Statements which update a row only where all columns which haven't been changed by the current user also haven't been changed in the database; if they have, someone else has changed the same row. Alternatively, you can add a column to all tables - version int not null - and update where the version hasn't changed since you read the object; you also increment the version number in every update.
If either method fails, you need to reread the now-current data and get your user to confirm or re-apply their changes. Bit of a pain but can be necessary.
I would advise you to move away from the Singleton pattern for testability: Dependency Injection & Singleton Design pattern
Instead, take a look at Dependency Injection. Ninject is a good way to start.
DI will take care of wiring the BO and DAL together:
public interface IUserRepository
{
IEnumerable<User> GetUsers();
}
public class UserBO
{
private readonly IUserRepository _userRepository;
public UserBO(IUserRepository userRepository){
_userRepository = userRepository;
}
public IEnumerable<User> GetUsers()
{
return _userRepository.GetUsers();
}
}
As for reusing the Connection Pool: Should you reuse SqlConnection, SqlDataAdapter, and SqlCommand objects?

Castle.Windsor lifestyle depending on context?

I have a web application where many components are registered using .LifestylePerWebRequest(), now I've decided to implement Quartz.NET, a .NET job scheduling library, which executes in separate threads, and not the Request thread.
As such, HttpContext.Current yields null. My services, repositories, and IDbConnection were instanced so far using .LifestylePerWebRequest() because it made it easier to dispose of them when the requests ended.
Now I want to use these components in both scenarios, during web requests I want them to remain unaffected, and in non-request contexts I want them to use a different Lifestyle, I figure I can handle the disposing myself, but how should I go about it for choosing a lifestyle for the components based on the current context?
Currently I register services (for example), like this:
container.Register(
AllTypes
.FromAssemblyContaining<EmailService>()
.Where(t => t.Name.EndsWith("Service"))
.WithService.Select(IoC.SelectByInterfaceConvention)
.LifestylePerWebRequest()
);
I figure I should be using some kind of extension method but I just don't see it..
You should use Hybrid Lifestyle from castleprojectcontrib.
An hybrid lifestyle is one that actually blends two underlying lifestyles: a main lifestyle and a secondary lifestyle. The hybrid lifestyle first tries to use the main lifestyle; if it's unavailable for some reason, it uses the secondary lifestyle. This is commonly used with PerWebRequest as the main lifestyle: if the HTTP context is available, it's used as the scope for the component instance; otherwise the secondary lifestyle is used.
Don't use the same components. In fact, in most scenarios I've seen the "background processing" doesn't even make sense to be in the web process to begin with.
Elaborating based on the comments.
Shoehorning background processing in the web pipeline is compromising your architecture to save a few $ on a EC2 instance. I would strongly suggest to think about this again, but I digress.
My statements still stands, even if you're putting both components in the web process they are two different components used in two different contexts and should be treated as such.
I've had a very similar problem recently - I wanted to be able to run initialisation code based off my container in the Application startup, when HttpContext.Request does not yet exist. I didn't find any way of doing it, so I modified the source of the PerWebRequestLifestyleModule to allow me to do what I wanted. Unfortunately it didn't seem possible to make this change without recompiling Windsor - I was hoping I would be able to do it in an extensible way so I could continue to use the main distribution of Windsor.
Anyway, to make this work, I modified the GetScope function of the PerWebRequestLifestyleModule so that if it was NOT running in a HttpContext (or if HttpContext.Request throws an exception, like it does in Application_Start) then it will look for a Scope started from the container instead. This allows me to use my container in Application_Start using the following code:
using (var scope = container.BeginScope())
{
// LifestylePerWebRequest components will now be scoped to this explicit scope instead
// _container.Resolve<...>()
}
There's no need to worry about explicitly disposing of things, because they will be disposed when the Scope is.
I've put the full code for the module below. I had to shuffle a couple of other things around within this class for it to work, but it's essentially the same.
public class PerWebRequestLifestyleModule : IHttpModule
{
private const string key = "castle.per-web-request-lifestyle-cache";
private static bool allowDefaultScopeOutOfHttpContext = true;
private static bool initialized;
public void Dispose()
{
}
public void Init(HttpApplication context)
{
initialized = true;
context.EndRequest += Application_EndRequest;
}
protected void Application_EndRequest(Object sender, EventArgs e)
{
var application = (HttpApplication)sender;
var scope = GetScope(application.Context, createIfNotPresent: false);
if (scope != null)
{
scope.Dispose();
}
}
private static bool IsRequestAvailable()
{
if (HttpContext.Current == null)
{
return false;
}
try
{
if (HttpContext.Current.Request == null)
{
return false;
}
return true;
}
catch (HttpException)
{
return false;
}
}
internal static ILifetimeScope GetScope()
{
var context = HttpContext.Current;
if (initialized)
{
return GetScope(context, createIfNotPresent: true);
}
else if (allowDefaultScopeOutOfHttpContext && !IsRequestAvailable())
{
// We're not running within a Http Request. If the option has been set to allow a normal scope to
// be used in this situation, we'll use that instead
ILifetimeScope scope = CallContextLifetimeScope.ObtainCurrentScope();
if (scope == null)
{
throw new InvalidOperationException("Not running within a Http Request, and no Scope was manually created. Either run from within a request, or call container.BeginScope()");
}
return scope;
}
else if (context == null)
{
throw new InvalidOperationException(
"HttpContext.Current is null. PerWebRequestLifestyle can only be used in ASP.Net");
}
else
{
EnsureInitialized();
return GetScope(context, createIfNotPresent: true);
}
}
/// <summary>
/// Returns current request's scope and detaches it from the request context.
/// Does not throw if scope or context not present. To be used for disposing of the context.
/// </summary>
/// <returns></returns>
internal static ILifetimeScope YieldScope()
{
var context = HttpContext.Current;
if (context == null)
{
return null;
}
var scope = GetScope(context, createIfNotPresent: true);
if (scope != null)
{
context.Items.Remove(key);
}
return scope;
}
private static void EnsureInitialized()
{
if (initialized)
{
return;
}
var message = new StringBuilder();
message.AppendLine("Looks like you forgot to register the http module " + typeof(PerWebRequestLifestyleModule).FullName);
message.AppendLine("To fix this add");
message.AppendLine("<add name=\"PerRequestLifestyle\" type=\"Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule, Castle.Windsor\" />");
message.AppendLine("to the <httpModules> section on your web.config.");
if (HttpRuntime.UsingIntegratedPipeline)
{
message.AppendLine(
"Windsor also detected you're running IIS in Integrated Pipeline mode. This means that you also need to add the module to the <modules> section under <system.webServer>.");
}
else
{
message.AppendLine(
"If you plan running on IIS in Integrated Pipeline mode, you also need to add the module to the <modules> section under <system.webServer>.");
}
#if !DOTNET35
message.AppendLine("Alternatively make sure you have " + PerWebRequestLifestyleModuleRegistration.MicrosoftWebInfrastructureDll +
" assembly in your GAC (it is installed by ASP.NET MVC3 or WebMatrix) and Windsor will be able to register the module automatically without having to add anything to the config file.");
#endif
throw new ComponentResolutionException(message.ToString());
}
private static ILifetimeScope GetScope(HttpContext context, bool createIfNotPresent)
{
var candidates = (ILifetimeScope)context.Items[key];
if (candidates == null && createIfNotPresent)
{
candidates = new DefaultLifetimeScope(new ScopeCache());
context.Items[key] = candidates;
}
return candidates;
}
}
Ok, I figured out a very clean way to do this!
First of all we'll need an implementation of IHandlerSelector, this can select a handler based on our opinion on the matter, or remain neutral (by returning null, which means "no opinion").
/// <summary>
/// Emits an opinion about a component's lifestyle only if there are exactly two available handlers and one of them has a PerWebRequest lifestyle.
/// </summary>
public class LifestyleSelector : IHandlerSelector
{
public bool HasOpinionAbout(string key, Type service)
{
return service != typeof(object); // for some reason, Castle passes typeof(object) if the service type is null.
}
public IHandler SelectHandler(string key, Type service, IHandler[] handlers)
{
if (handlers.Length == 2 && handlers.Any(x => x.ComponentModel.LifestyleType == LifestyleType.PerWebRequest))
{
if (HttpContext.Current == null)
{
return handlers.Single(x => x.ComponentModel.LifestyleType != LifestyleType.PerWebRequest);
}
else
{
return handlers.Single(x => x.ComponentModel.LifestyleType == LifestyleType.PerWebRequest);
}
}
return null; // we don't have an opinion in this case.
}
}
I made it so the opinion is very limited on purpose. I'll be having an opinion only if there are exactly two handlers and one of them has PerWebRequest lifestyle; meaning the other one is probably the non-HttpContext alternative.
We need to register this selector with Castle. I do so before I start registering any other components:
container.Kernel.AddHandlerSelector(new LifestyleSelector());
Lastly I wish I had any clue as to how I could copy my registration to avoid this:
container.Register(
AllTypes
.FromAssemblyContaining<EmailService>()
.Where(t => t.Name.EndsWith("Service"))
.WithService.Select(IoC.SelectByInterfaceConvention)
.LifestylePerWebRequest()
);
container.Register(
AllTypes
.FromAssemblyContaining<EmailService>()
.Where(t => t.Name.EndsWith("Service"))
.WithService.Select(IoC.SelectByInterfaceConvention)
.LifestylePerThread()
);
If you can figure out a way to clone a registration, change the lifestyle and register both of them (using either container.Register or IRegistration.Register), please post it as an answer here! :)
Update: In testing, I need to uniquely name the identical registrations, I did so like this:
.NamedRandomly()
public static ComponentRegistration<T> NamedRandomly<T>(this ComponentRegistration<T> registration) where T : class
{
string name = registration.Implementation.FullName;
string random = "{0}{{{1}}}".FormatWith(name, Guid.NewGuid());
return registration.Named(random);
}
public static BasedOnDescriptor NamedRandomly(this BasedOnDescriptor registration)
{
return registration.Configure(x => x.NamedRandomly());
}
I don't know whats happening behind the scenes in .LifestylePerWebRequest(); but this is what I do for "Context per request" scenarios:
Check HttpContext for session and if exists pull the context from .Items.
If it doesn't exist pull your context from System.Threading.Thread.CurrentContext.
Hope this helps.

How to initialise a custom HTTP Context or HttpContextBase

I am experimenting with creating my own custom HTTP Context:
CustomHttpContext : HttpContextBase
{
public override HttpRequestBase Request { }
}
One thing i can't figure out is how to initialize the base class with
System.Web.HttpContext.Current
Does anyone have any ideas how i can initialise the custom context first with the Current Http then override certain Methods/Properties to serve my own purpose?
The simple answer is no, it's not possible. Also note that HttpContext does not inherit from HttpContextBase, instead, they both implement IServiceProvider. Finally, HttpContext is sealed, suggesting that the authors did not want people to do anything other than consume this class.
As you are no doubt annoyed by HttpContextBase has a parameterless constructor so does not even give you the option of instantiating it from the current request and response like HttpContext!
Let's use a 'decompiler' to take a look at the implementation of HttpContext.Current:
// System.Web.HttpContext
/// <summary>Gets or sets the <see cref="T:System.Web.HttpContext" /> object for the current HTTP request.</summary>
/// <returns>The <see cref="T:System.Web.HttpContext" /> for the current HTTP request.</returns>
public static HttpContext Current
{
get
{
return ContextBase.Current as HttpContext;
}
set
{
ContextBase.Current = value;
}
}
If we take a look at ContextBase.Current (from System.Web.Hosting.ContextBase):
// System.Web.Hosting.ContextBase
internal static object Current
{
get
{
return CallContext.HostContext;
}
[SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
set
{
CallContext.HostContext = value;
}
}
and CallContext (in System.Runtime.Messaging):
// System.Runtime.Remoting.Messaging.CallContext
/// <summary>Gets or sets the host context associated with the current thread.</summary>
/// <returns>The host context associated with the current thread.</returns>
/// <exception cref="T:System.Security.SecurityException">The immediate caller does not have infrastructure permission. </exception>
public static object HostContext
{
[SecurityCritical]
get
{
IllogicalCallContext illogicalCallContext = Thread.CurrentThread.GetIllogicalCallContext();
object hostContext = illogicalCallContext.HostContext;
if (hostContext == null)
{
LogicalCallContext logicalCallContext = CallContext.GetLogicalCallContext();
hostContext = logicalCallContext.HostContext;
}
return hostContext;
}
[SecurityCritical]
set
{
if (value is ILogicalThreadAffinative)
{
IllogicalCallContext illogicalCallContext = Thread.CurrentThread.GetIllogicalCallContext();
illogicalCallContext.HostContext = null;
LogicalCallContext logicalCallContext = CallContext.GetLogicalCallContext();
logicalCallContext.HostContext = value;
return;
}
LogicalCallContext logicalCallContext2 = CallContext.GetLogicalCallContext();
logicalCallContext2.HostContext = null;
IllogicalCallContext illogicalCallContext2 = Thread.CurrentThread.GetIllogicalCallContext();
illogicalCallContext2.HostContext = value;
}
}
We start to get a feel for how the HttpContext is being retrieved. It's being packaged in with the thread the current user started when they visted the website (which makes perfect sense!). Delving further we can see it also gets recreated per request (see below).
We can also see, at the interface layer, HttpContext.Current cannot be changed to point at your own HttpContext as the property is not virtual. It also uses many BCL classes that are private or internal so you can't simply copy most of the implementation.
What would be easier, and also less prone to any other issues would be to simply wrap HttpContext with your own CustomContext object. You could simply wrap HttpContext.Current in a BaseContext property, then have your own properties on the class (and use whatever session, database, or request based state storage mechanism you want to store and retrieve your own properties).
Personally, I'd use my own class for storing my own information, as it belongs to my application and user etc and isn't really anything to do with the http pipeline or request/response processing.
See also:
ASP.NET MVC : How to create own HttpContext
How is HttpContext being maintained over request-response
Just to add on a bit to dash's answer, you can also use the [ThreadStatic] attribute with some static property. Initialize it on BeginRequest, either by using global.cs or by writing your own HttpModule/HttpHandler.
How to create a web module:
http://msdn.microsoft.com/en-us/library/ms227673(v=vs.100).aspx
Thread static:
http://msdn.microsoft.com/en-us/library/system.threadstaticattribute.aspx

Async WCF: wait for another call

We have an old Silverlight UserControl + WCF component in our framework and we would like to increase the reusability of this feature. The component should work with basic functionality by default, but we would like to extend it based on the current project (without modifying the original, so more of this control can appear in the full system with different functionality).
So we made a plan, where everything looks great, except one thing. Here is a short summary:
Silverlight UserControl can be extended and manipulated via ContentPresenter at the UI and ViewModel inheritance, events and messaging in the client logic.
Back-end business logic can be manipulated with module loading.
This gonna be okay I think. For example you can disable/remove fields from the UI with overriden ViewModel properties, and at the back-end you can avoid some action with custom modules.
The interesting part is when you add new fields via the ContentPresenter. Ok, you add new properties to the inherited ViewModel, then you can bind to them. You have the additional data. When you save base data, you know it's succeeded, then you can start saving your additional data (additional data can be anything, in a different table at back-end for example). Fine, we extended our UserControl and the back-end logic and the original userControl still doesn't know anything about our extension.
But we lost transaction. For example we can save base data, but additional data saving throws an exception, we have the updated base data but nothing in the additional table. We really doesn't want this possibility, so I came up with this idea:
One WCF call should wait for the other at the back-end, and if both arrived, we can begin cross thread communication between them, and of course, we can handle the base and the additional data in the same transaction, and the base component still doesn't know anything about the other (it just provide a feature to do something with it, but it doesn't know who gonna do it).
I made a very simplified proof of concept solution, this is the output:
1 send begins
Press return to send the second piece
2 send begins
2 send completed, returned: 1
1 send completed, returned: 2
Service
namespace MyService
{
[ServiceContract]
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Service1
{
protected bool _sameArrived;
protected Piece _same;
[OperationContract]
public Piece SendPiece(Piece piece)
{
_sameArrived = false;
Mediator.Instance.WaitFor(piece, sameArrived);
while (!_sameArrived)
{
Thread.Sleep(100);
}
return _same;
}
protected void sameArrived(Piece piece)
{
_same = piece;
_sameArrived = true;
}
}
}
Piece (entity)
namespace MyService
{
[DataContract]
public class Piece
{
[DataMember]
public long ID { get; set; }
[DataMember]
public string SameIdentifier { get; set; }
}
}
Mediator
namespace MyService
{
public sealed class Mediator
{
private static Mediator _instance;
private static object syncRoot = new Object();
private List<Tuple<Piece, Action<Piece>>> _waitsFor;
private Mediator()
{
_waitsFor = new List<Tuple<Piece, Action<Piece>>>();
}
public static Mediator Instance
{
get
{
if (_instance == null)
{
lock (syncRoot)
{
_instance = new Mediator();
}
}
return _instance;
}
}
public void WaitFor(Piece piece, Action<Piece> callback)
{
lock (_waitsFor)
{
var waiter = _waitsFor.Where(i => i.Item1.SameIdentifier == piece.SameIdentifier).FirstOrDefault();
if (waiter != null)
{
_waitsFor.Remove(waiter);
waiter.Item2(piece);
callback(waiter.Item1);
}
else
{
_waitsFor.Add(new Tuple<Piece, Action<Piece>>(piece, callback));
}
}
}
}
}
And the client side code
namespace MyClient
{
class Program
{
static void Main(string[] args)
{
Client c1 = new Client(new Piece()
{
ID = 1,
SameIdentifier = "customIdentifier"
});
Client c2 = new Client(new Piece()
{
ID = 2,
SameIdentifier = "customIdentifier"
});
c1.SendPiece();
Console.WriteLine("Press return to send the second piece");
Console.ReadLine();
c2.SendPiece();
Console.ReadLine();
}
}
class Client
{
protected Piece _piece;
protected Service1Client _service;
public Client(Piece piece)
{
_piece = piece;
_service = new Service1Client();
}
public void SendPiece()
{
Console.WriteLine("{0} send begins", _piece.ID);
_service.BeginSendPiece(_piece, new AsyncCallback(sendPieceCallback), null);
}
protected void sendPieceCallback(IAsyncResult result)
{
Piece returnedPiece = _service.EndSendPiece(result);
Console.WriteLine("{0} send completed, returned: {1}", _piece.ID, returnedPiece.ID);
}
}
}
So is it a good idea to wait for another WCF call (which may or may not be invoked, so in a real example it would be more complex), and process them together with cross threading communication? Or not and I should look for another solution?
Thanks in advance,
negra
If you want to extend your application without changing any existing code, you can use MEF that is Microsoft Extensibility Framework.
For using MEF with silverlight see: http://development-guides.silverbaylabs.org/Video/Silverlight-MEF
I would not wait for 2 WCF calls from Silverlight, for the following reasons:
You are making your code more complex and less maintainable
You are storing business knowledge, that two services should be called together, in the client
I would call a single service that aggreagated the two services.
It doesn't feel like a great idea to me, to be honest. I think it would be neater if you could package up both "partial" requests in a single "full" request, and wait for that. Unfortunately I don't know the best way of doing that within WCF. It's possible that there's a generalized mechanism for this, but I don't know about it. Basically you'd need some loosely typed service layer where you could represent a generalized request and a generalized response, routing the requests appropriately in the server. You could then represent a collection of requests and responses easily.
That's the approach I'd look at, personally - but I don't know how neatly it will turn out in WCF.

Entity Framework Best Practices In Business Logic?

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)

Categories