Disposing ObjectResult<T> - entity-framework-4

I've started using Entity Framework (database first), and I noticed that the methods the tt template generates for the context class (for stored procedures) have a return type ofObjectResult.
This type is IDisposable, but no sample code I can find actually calls the Dispose method. Is there a reason for this?
I currently don't have the "using" on the stored procedure call as I do further IEnumerable related stuff on the result (essentially just projecting the result set), but I could easily refactor that.
My question is, should I be using a pattern like the following if I have no reason to keep the connection to the database open:
using (var context = new DatabaseContext())
{
using (var result = context.spMyStoredProcedure(param1, param2))
{
return result.ToList();
}
}
I've seen some advice that even disposing the DbContext might not be needed, but there seems to be a lot of inconsistencies even on MSDN on what to do.

I decompiled ObjectResult<T> (EF4.) Here's its Dispose() method. It's creating other managed objects, like a DbDataReader. and an internal object called a Shaper that can own a database connection.
If you dispose it, you're trusting it to know what it's doing. If you don't, you trust yourself to know what it's doing, not doing, and why. I'd play it safe and dispose it.
public override void Dispose()
{
DbDataReader reader = this._reader;
this._reader = (DbDataReader) null;
this._nextResultGenerator = (NextResultGenerator) null;
if (reader != null && this._readerOwned)
{
reader.Dispose();
if (this._onReaderDispose != null)
{
this._onReaderDispose((object) this, new EventArgs());
this._onReaderDispose = (Action<object, EventArgs>) null;
}
}
if (this._shaper == null)
return;
if (this._shaper.Context != null && this._readerOwned)
this._shaper.Context.ReleaseConnection();
this._shaper = (Shaper<T>) null;
}

Related

EF DbContext Attach works only when proxy creation disabled

I ran into an issue where I was intermittently receiving an error:
An entity object cannot be referenced by multiple instances of IEntityChangeTracker
whenever trying to attach an entity to the DbContext.
UPDATE: Original post is below and is TL;DR. So here is a simplified version with more testing.
First I get the Documents collection. There are 2 items returned in this query.
using (UnitOfWork uow = new UnitOfWork())
{
// uncomment below line resolves all errors
// uow.Context.Configuration.ProxyCreationEnabled = false;
// returns 2 documents in the collection
documents = uow.DocumentRepository.GetDocumentByBatchEagerly(skip, take).ToList();
}
Scenario 1:
using (UnitOfWork uow2 = new UnitOfWork())
{
// This errors ONLY if the original `uow` context is not disposed.
uow2.DocumentRepository.Update(documents[0]);
}
This scenario works as expected. I can force the IEntityChangeTracker error by NOT disposing the original uow context.
Scenario 2:
Iterate through the 2 items in the documents collection.
foreach (Document document in documents)
{
_ = Task.Run(() =>
{
using (UnitOfWork uow3 = new UnitOfWork())
{
uow3.DocumentRepository.Update(document);
});
}
}
Both items fail to attach to the DbSet with the IEntityChangeTracker error. Sometimes one succeeds and only one fails. I assume this might be to do with the exact timings of the Task Scheduler. But even if they are attaching concurrently, they are different document entities. So they shouldn't be being tracked by any other context. Why am I getting the error?
If I uncomment ProxyCreationEnabled = false on the original uow context, this scenario works! So how are they still being tracked even thought the context was disposed? Why is it a problem that they are DynamicProxies, even though they are not attached to or tracked by any context.
ORIGINAL POST:
I have an entity object called Document, and it's related entity which is a collection of DocumentVersions.
In the code below, the document object and all related entities including DocumentVersions have already been eagerly loaded before being passed to this method - which I will demonstrate after.
public async Task PutNewVersions(Document document)
{
// get versions
List<DocumentVersion> versions = document.DocumentVersions.ToList();
for (int i = 0; i < versions.Count; i++)
{
UnitOfWork uow = new UnitOfWork();
try
{
versions[i].Attempt++;
//... make some API call that succeeds
versions[i].ContentUploaded = true;
versions[i].Result = 1;
}
finally
{
uow.DocumentVersionRepository.Update(versions[i]); // error hit in this method
uow.Save();
}
}
}
The Update method just attaches the entity and changes the state. It is part of a GenericRepository class that all my Entity Repositories inherit from:
public virtual void Update(TEntity entityToUpdate)
{
dbSet.Attach(entityToUpdate); // error is hit here
context.Entry(entityToUpdate).State = EntityState.Modified;
}
The document entity, and all related entities are loaded eagerly using a method in the Document entity repository:
public class DocumentRepository : GenericRepository<Document>
{
public DocumentRepository(MyEntities context) : base(context)
{
this.context = context;
}
public IEnumerable<Document> GetDocumentByBatchEagerly(int skip, int take)
{
return (from document in context.Documents
.Include(...)
.Include(...)
.Include(...)
.Include(...)
.Include(d => d.DocumentVersions)
.AsNoTracking()
orderby document.DocumentKey descending
select document).Skip(skip).Take(take);
}
}
The method description for .AsNoTracking() says that "the entities returned will not be cached in the DbContext". Great!
Then why does the .Attach() method above think that this DocumentVersion entity is already referenced in another IEntityChangeTracker? I am assuming this means it is referenced in another DbContext, i.e: the one calling GetDocumentByBatchEagerly(). And why does this issue only present intermittently? It seems that it happens less often when I am stepping through the code.
I resolved this by adding the following line to the above DocumentRepository constructor:
this.context.Configuration.ProxyCreationEnabled = false;
I just don't understand why this appears to resolve the issue.
It also means if I ever want to use the DocumentRepository for something else and want to leverage change tracking and lazy loading, I can't. There doesn't seem to be a 'per query' option to turn off dynamic proxies like there is with 'as no tracking'.
For completeness, here is how the 'GetDocumentsByBatchEagerly' method is being used, to demonstrate that it uses it's own instance of UnitOfWork:
public class MigrationHandler
{
UnitOfWork uow = new UnitOfWork();
public async Task FeedPipelineAsync()
{
bool moreResults = true;
do
{
// documents retrieved with AsNoTracking()
List<Document> documents = uow.DocumentRepository.GetDocumentByBatchEagerly(skip, take).ToList();
if (documents.Count == 0) moreResults = false;
skip += take;
// push each record into TPL Dataflow pipeline
foreach (Document document in documents)
{
// Entry point for the data flow pipeline which links to
// a block that calls PutNewVersions()
await dataFlowPipeline.DocumentCreationTransformBlock.SendAsync(document);
}
} while (moreResults);
dataFlowPipeline.DocumentCreationTransformBlock.Complete();
// await completion of each block at the end of the pipeline
await Task.WhenAll(
dataFlowPipeline.FileDocumentsActionBlock.Completion,
dataFlowPipeline.PutVersionActionBlock.Completion);
}
}

Session becomes null in different thread

I have a task that runs in a different thread and requires the session. I've done:
public GenerateDocList(LLStatistics.DocLists.DocList docs)
{
this.docs = docs;
context = HttpContext.Current;
}
and
public void StartTask()
{
//this code runs in a separate thread
HttpContext.Current = context;
/* rest of the code */
}
Now the thread has knowledge of the session and it works for a while but at some point in my loop HttpContext.Current.Session becomes null. Any ideas what can I do about this?
public static LLDAC.DAL.DBCTX LLDB
{
get
{
LLDAC.DAL.DBCTX currentUserDBContext = HttpContext.Current.Session["LLDBContext"] as LLDAC.DAL.DBCTX;
if (currentUserDBContext == null)
{
currentUserDBContext = new LLDAC.DAL.DBCTX();
HttpContext.Current.Session.Add("LLDBContext", currentUserDBContext);//this works only for a few loop iterations
}
return currentUserDBContext;
}
}
In general, this is a very fragile pattern for a multi-threaded operation. Long-running tasks (which I assume this is) are best suited to instance methods in a class rather than static methods such that the class can maintain any dependent objects. Also, since the session state is not thread safe and can span multiple requests you are getting into some very risky business by cashing your DB context in the session at all.
If you are convinced this is best done with static methods and stored in the session, you may be able to do something like this:
public static HttpSessionState MySession { get; set; }
public GenerateDocList(LLStatistics.DocLists.DocList docs)
{
this.docs = docs;
MySession = HttpContext.Current.Session;
}
Then:
public static LLDAC.DAL.DBCTX LLDB
{
get
{
LLDAC.DAL.DBCTX currentUserDBContext = MySession["LLDBContext"] as LLDAC.DAL.DBCTX;
if (currentUserDBContext == null)
{
currentUserDBContext = new LLDAC.DAL.DBCTX();
if (MySession == null)
{
thow new InvalidOperaionException("MySession is null");
}
MySession.Add("LLDBContext", currentUserDBContext);
}
return currentUserDBContext;
}
}
Note that you could still run into issues with the session since other threads could still modify the session.
A better solution would probably look something like this:
public class DocListGenerator : IDisposable
{
public LLDAC.DAL.DBCTX LLDB { get; private set; }
public DocListGenerator()
{
LLDB = new LLDAC.DAL.DBCTX();
}
public void GenerateList()
{
// Put loop here.
}
public void Dispose()
{
if (LLDB != null)
{
LLDB.Dispose();
}
}
}
Then your calling code looks like this:
public void StartTask()
{
using (DocListGenerator generator = new DocListGenerator()
{
generator.GenerateList();
}
}
If you really want to cache something, you could cache your instance like this:
HttpContext.Current.Sesssion.Add("ListGenerator", generator);
However, I still don't think that is a particularly good idea since your context could still be disposed or otherwise altered by a different thread.
Using anything related to the HttpContext.Current on anything besides the main Request thread is generally going to get you into trouble in ASP.net.
The HttpContext is actually backed on a thread belonging to a Thread Pool and the thread may very well get reused on another request.
This is actually a common issue with using the new Async/Await keywords in ASP.net as well.
In order to help you, it would help to know why you're attempting this in the first place?
Is this a single server or a web farm with multiple load balanced servers?
Are you hosting it yourself, or is it the site hosted by a provider?
What is the SessionState implementation (SQL Server, State Server, In-Process, or something custom like MemCached, Redis, etc...)
What version of ASP .net?
Why are you starting a new thread instead of just doing the processing on the request thread?
If you really can't (or shouldn't) use session. Then you could use something like a correlation ID.
Guid correlationID = Guid.NewGuid();
HttpContext.Current.Session["DocListID"] = correlationID;
DocList.GoOffAndGenerateSomeStuffOnANewThread(correlationID);
... when process is done, store the results somewhere using the specified ID
// Serialize the result to SQL server, the file system, cache...
DocList.StoreResultsSomewhereUnderID();
... later on
DocList.CheckForResultsUnderID(HttpContext.Current.Session["DocListID"]);

Accessing encoded stream in OpenRasta

I have a need to access the encoded stream in OpenRasta before it gets sent to the client. I have tried using a PipelineContributor and registering it before KnownStages.IEnd, tried after KnownStages.IOperationExecution and after KnownStages.AfterResponseConding but in all instances the context.Response.Entity stream is null or empty.
Anyone know how I can do this?
Also I want to find out the requested codec fairly early on yet when I register after KnowStages.ICodecRequestSelection it returns null. I just get the feeling I am missing something about these pipeline contributors.
Without writing your own Codec (which, by the way, is really easy), I'm unaware of a way to get the actual stream of bytes sent to the browser. The way I'm doing this is serializing the ICommunicationContext.Response.Entity before the IResponseCoding known stage. Pseudo code:
class ResponseLogger : IPipelineContributor
{
public void Initialize(IPipeline pipelineRunner)
{
pipelineRunner
.Notify(LogResponse)
.Before<KnownStages.IResponseCoding>();
}
PipelineContinuation LogResponse(ICommunicationContext context)
{
string content = Serialize(context.Response.Entity);
}
string Serialize(IHttpEntity entity)
{
if ((entity == null) || (entity.Instance == null))
return String.Empty;
try
{
using (var writer = new StringWriter())
{
using (var xmlWriter = XmlWriter.Create(writer))
{
Type entityType = entity.Instance.GetType();
XmlSerializer serializer = new XmlSerializer(entityType);
serializer.Serialize(xmlWriter, entity.Instance);
}
return writer.ToString();
}
}
catch (Exception exception)
{
return exception.ToString();
}
}
}
This ResponseLogger is registered the usual way:
ResourceSpace.Uses.PipelineContributor<ResponseLogger>();
As mentioned, this doesn't necessarily give you the exact stream of bytes sent to the browser, but it is close enough for my needs, since the stream of bytes sent to the browser is basically just the same serialized entity.
By writing your own codec, you can with no more than 100 lines of code tap into the IMediaTypeWriter.WriteTo() method, which I would guess is the last line of defense before your bytes are transferred into the cloud. Within it, you basically just do something simple like this:
public void WriteTo(object entity, IHttpEntity response, string[] parameters)
{
using (var writer = XmlWriter.Create(response.Stream))
{
XmlSerializer serializer = new XmlSerializer(entity.GetType());
serializer.Serialize(writer, entity);
}
}
If you instead of writing directly to to the IHttpEntity.Stream write to a StringWriter and do ToString() on it, you'll have the serialized entity which you can log and do whatever you want with before writing it to the output stream.
While all of the above example code is based on XML serialization and deserialization, the same principle should apply no matter what format your application is using.

Windsor Interceptor Exception

I have a Windsor container that I'm using an InterceptorSelector and a LazyComponentLoader with.
My InterceptorSelector returns an InterceptorReference to my InterceptorAdapter class that looks like this
public class InterceptorAdapter<T> : Castle.DynamicProxy.IInterceptor, IOnBehalfAware where T : IMyType
{
private readonly T interceptor;
public InterceptorAdapter(T interceptor)
{
this.interceptor = interceptor;
}
....
}
so the InterceptorSelector does
public InterceptorReference[] SelectInterceptors(ComponentModel model, InterceptorReference[] interceptors)
{
var results = new List<InterceptorReference>();
....
foreach (var interceptorType in someInterceptorTypes)
{
Type interceptorAdapterType = typeof(InterceptorAdapter<>).MakeGenericType(interceptorType);
if (kernel.GetHandler(interceptorAdapterType) == null)
{
// need to do this or Castle complains it can't create my
// interceptor...I guess LazyComponentLoaders don't work for InterceptorReferences?...
// I suspect the problem may be here...
kernel.Register(lazyComponentLoader.Load(null, interceptorAdapterType, null));
}
results.Add(InterceptorReference.ForType(interceptorAdapterType));
}
return results.ToArray();
}
Things work great the first time my InterceptorSelector returns an InterceptorReference. The next time, when it returns an InterceptorReference to an InterceptorAdapter with a different generic type argument, I get
Castle.MicroKernel.ComponentRegistrationException occurred
Message=There is a component already registered for the given key interceptor
Source=Castle.Windsor
StackTrace:
at Castle.MicroKernel.SubSystems.Naming.DefaultNamingSubSystem.Register(String key, IHandler handler) in c:\TeamCity\buildAgent\work\1ab5e0b25b145b19\src\Castle.Windsor\MicroKernel\SubSystems\Naming\DefaultNamingSubSystem.cs:line 75
InnerException:
My LazyComponentLoader simply does
public IRegistration Load(string key, Type service, IDictionary arguments)
{
ComponentRegistration<object> component = Component.For(service).Named(key);
if (arguments != null)
{
// merge is an extension method to merge dictionaries.
component.DynamicParameters((k, d) => d.Merge(arguments));
}
return component;
}
My container setup looks like
var container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.AddFacility("factories", new FactorySupportFacility());
container.Register(Component.For<ILazyComponentLoader>().ImplementedBy<MyLazyComponentLoader>().LifeStyle.Singleton);
container.Kernel.ProxyFactory.AddInterceptorSelector(new InterceptorSelector(container.Kernel, container.Resolve<ILazyComponentLoader>()));
Any suggestions?
Thanks!
This seems to be a problem in the way Castle resolves Interceptors using an LazyComponentLoader.
Changing my code in the selector to do:
if (kernel.GetHandler(interceptorType) == null)
{
// need to do this or Castle complains it can't create my
// interceptor...I guess LazyComponentLoaders don't work for InterceptorReferences?...
// I suspect the problem may be here...
kernel.Register(lazyComponentLoader.Load(null, interceptorType, null));
}
Type interceptorAdapterType = typeof(InterceptorAdapter<>).MakeGenericType(interceptorType);
if (kernel.GetHandler(interceptorAdapterType) == null)
{
// need to do this or Castle complains it can't create my
// interceptor...I guess LazyComponentLoaders don't work for InterceptorReferences?...
// I suspect the problem may be here...
kernel.Register(lazyComponentLoader.Load(null, interceptorAdapterType, null));
}
Seems to fix the problem.

Asp.net Mvc - Kigg: Maintain User object in HttpContext.Items between requests

first I want to say that I hope this doesn't look like I am lazy but I have some trouble understanding a piece of code from the following project.
http://kigg.codeplex.com/
I was going through the source code and I noticed something that would be usefull for my own little project I am making. In their BaseController they have the following code:
private static readonly Type CurrentUserKey = typeof(IUser);
public IUser CurrentUser
{
get
{
if (!string.IsNullOrEmpty(CurrentUserName))
{
IUser user = HttpContext.Items[CurrentUserKey] as IUser;
if (user == null)
{
user = AccountRepository.FindByClaim(CurrentUserName);
if (user != null)
{
HttpContext.Items[CurrentUserKey] = user;
}
}
return user;
}
return null;
}
}
This isn't an exact copy of the code I adjusted it a little to my needs. This part of the code I still understand. They store their IUser in HttpContext.Items. I guess they do it so that they don't have to call the database eachtime they need the User object.
The part that I don't understand is how they maintain this object in between requests. If I understand correctly the HttpContext.Items is a per request cache storage.
So after some more digging I found the following code.
internal static IDictionary<UnityPerWebRequestLifetimeManager, object> GetInstances(HttpContextBase httpContext)
{
IDictionary<UnityPerWebRequestLifetimeManager, object> instances;
if (httpContext.Items.Contains(Key))
{
instances = (IDictionary<UnityPerWebRequestLifetimeManager, object>) httpContext.Items[Key];
}
else
{
lock (httpContext.Items)
{
if (httpContext.Items.Contains(Key))
{
instances = (IDictionary<UnityPerWebRequestLifetimeManager, object>) httpContext.Items[Key];
}
else
{
instances = new Dictionary<UnityPerWebRequestLifetimeManager, object>();
httpContext.Items.Add(Key, instances);
}
}
}
return instances;
}
This is the part where some magic happens that I don't understand. I think they use Unity to do some dependency injection on each request? In my project I am using Ninject and I am wondering how I can get the same result.
I guess InRequestScope in Ninject is the same as UnityPerWebRequestLifetimeManager? I am also wondering which class/method they are binding to which interface? Since the HttpContext.Items get destroyed each request how do they prevent losing their user object?
Anyway it's kinda a long question so I am grateful for any push in the right direction.
In Ninject, you pick your tech-specific extension (Ninject.Web or Ninject.Web.Mvc) and use InRequestScope to manage stuff in 'the .Items context'. They get Disposed at the end of the request and fresh ones will be Resolved as needed on subsequent requests.
It definitely wont be as much code or as complex as some of the stuff you're citing IMO :D

Resources