ObjectDisposedException While using Include - why? - asp.net

My page calls a Services layer method that uses a Generic Repository "Find" method. In the services layer method, I do the following:
using (IUnitOfWork unitOfWork = new DBContext())
{
GenericRepository<Operator> operatorRepos = new GenericRepository<Operator>(unitOfWork);
{
try
{
var oper = operatorRepos.Find(o => o.OperatorID == operatorID).Include(o => o.cmn_Address).Single();
return oper;
}
catch (InvalidOperationException exc)
{
//handle exception
}
}
}
The Find method for my repository:
public IQueryable<T> Find(Func<T, bool> predicate)
{
return _objectSet.Where<T>(predicate).AsQueryable();
}
On the page, I try to access the cmn_address Navigation property of the Operator and I get the following error:
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
I realize that this is caused by the using statement to dispose of the context, but I thought the Include method will eager load the cmn_Address object. I don't understand why this doesn't work as I expected.

You are using Func<> instead of Expression<Func<>> in your where condition. That makes it Linq-to-objects. This change is permanent. Calling AsQueryable doesn't make it Linq-to-entities again.

Related

Async task ASP.net HttpContext.Current.Items is empty - How do handle this?

We are running a very large web application in asp.net MVC .NET 4.0. Recently we had an audit done and the performance team says that there were a lot of null reference exceptions.
So I started investigating it from the dumps and event viewer.
My understanding was as follows:
We are using Asyn Tasks in our controllers. We rely on HttpContext.Current.Items hashtable to store a lot of Application level values.
Task<Articles>.Factory.StartNew(() =>
{
System.Web.HttpContext.Current = ControllerContext.HttpContext.ApplicationInstance.Context;
var service = new ArticlesService(page);
return service.GetArticles();
}).ContinueWith(t => SetResult(t, "articles"));
So we are copying the context object onto the new thread that is spawned from Task factory. This context.Items is used again in the thread wherever necessary.
Say for ex:
public class SomeClass
{
internal static int StreamID
{
get
{
if (HttpContext.Current != null)
{
return (int)HttpContext.Current.Items["StreamID"];
}
else
{
return DEFAULT_STREAM_ID;
}
}
}
This runs fine as long as number of parallel requests are optimal. My questions are as follows:
1. When the load is more and there are too many parallel requests, I notice that HttpContext.Current.Items is empty. I am not able to figure out a reason for this and this causes all the null reference exceptions.
2. How do we make sure it is not null ? Any workaround if present ?
NOTE: I read through in StackOverflow and people have questions like HttpContext.Current is null - but in my case it is not null and its empty. I was reading one more article where the author says that sometimes request object is terminated and it may cause problems since dispose is already called on objects. I am doing a copy of Context object - its just a shallow copy and not a deep copy.
Your problem is that a instance members of the HttpContext are not thread safe:
Any public static (Shared in Visual Basic) members of this type are
thread safe. Any instance members are not guaranteed to be thread
safe.
When accessing it the way you are doing (multiple threads) you need to do your own synchronization.
static object locker = new object();
get
{
lock (locker)
{
if (HttpContext.Current != null)
{
return (int)HttpContext.Current.Items["StreamID"];
}
else
{
return DEFAULT_STREAM_ID;
}
}
}
MSDN: system.web.httpcontext
Maybe I'm misreading this, but I'm getting the impression that you're only trying to prevent the null reference error.
public class SomeClass
{
internal static int StreamID
{
get
{
int returnValue;
if (HttpContext.Current != null)
{
if(HttpContext.Current.Items["StreamID"] != null)
{
returnValue = (int)HttpContext.Current.Items["StreamID"];
}
else
{
returnValue = DEFAULT_STREAM_ID;
}
}
else
{
returnValue = DEFAULT_STREAM_ID;
}
return returnValue;
}
}
}

FakeMessageContext throws NullReferenceException

I'm trying to write unit test for my saga. I have used SagaFixture to host my Saga and using FakeBus. I have also used FakeMessageContext because, in a Saga exectution I'm using MessageContext to get return address.
Now, when I'm trying to call Handle method on Fixture, it throws exception of type NullReferenceException.
Pasting code below:
SearchSaga
public class SearchSaga : Saga<SearchSagaData>, IAmInitiatedBy<PersonRequested>, IHandleMessages<PersonSearchCompleted>
{
public void Handle(PersonRequested message)
{
Data.Id = new Guid(message.MessageId);
Data.ReturnAddress = MessageContext.GetCurrent().ReturnAddress;
Bus.Publish(message);
}
}
SagaUnitTest
[Test]
public void PublishResponseOfTypeSearchPersonRequest()
{
var bus = new FakeBus();
var saga = new SearchSaga(bus);
var fixture = new SagaFixture<SearchSagaData>(saga);
FakeMessageContext.Reset();
var fakeContext = MockRepository.GenerateMock<IMessageContext>();
fakeContext.Stub(s => s.ReturnAddress).Return("queuename");
fakeContext.Stub(s => s.Headers).Return(new Dictionary<string, object>());
// act
using (FakeMessageContext.Establish(fakeContext))
{
fixture.Handle(new PersonRequested {MessageId = Guid.NewGuid().ToString(), Query = "Abc"});
}
var sentRequests = bus.PublishedMessages.OfType<SearchPersonRequest>().ToList();
Assert.That(sentRequests.Count, Is.EqualTo(1));
}
Error Stacktrace:
at Rebus.SagaContext..ctor(Guid id)
at Rebus.Bus.Dispatcher.DispatchToHandler[TMessage](TMessage message, IHandleMessages1 handler) at Rebus.Testing.SagaFixture1.Handle[TMessage](TMessage message)
The exception is caused by the fact that your IMessageContext mock has a null value on the Items property. The thrown exception is just pretty bad, but I'll make sure that the reported error gets better in the future.
For now, you can fix the situation by setting up a an items dictionary like so:
fakeContext.Stub(s => s.Items).Return(new Dictionary<string, object>());
Moreover, instead of using MessageContext.GetCurrent() to get to the message context inside your handler, you should take advantage of the fact that all Rebus' IoC container adapters ensure that you can have an IMessageContext injected into all of your handler instances.
This way, there's no need to use FakeMessageContext in your unit tests.

Setting exception handled in Web API ExceptionFilterAttribute

Is there any way in ASP.NET Web API to mark an exception as handled in an ExceptionFilterAttribute?
I want to handle the exception at the method level with an exception filter and stop the propagation to a globally registered exception filter.
Filter used on a controller action:
public class MethodExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception is NotImplementedException)
{
context.Response = new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent(context.Exception.Message)
};
// here in MVC you could set context.ExceptionHandled = true;
}
}
}
The globally registered filter:
public class GlobalExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception is SomeOtherException)
{
context.Response = new HttpResponseMessage(HttpStatusCode.SomethingElse)
{
Content = new StringContent(context.Exception.Message)
};
}
}
}
Try throwing an HttpResponseException at the end of your local handling. By design, they are not caught by exception filters.
throw new HttpResponseException(context.Response);
Web API 2 is designed with inversion of control in mind. You consider the possibility for the exception to already be handled, rather than interrupting the filter execution after you handle it.
In this sense, attributes deriving from ExceptionFilterAttribute should check if the exception is already handled, which your code already does since is operator returns false for null values. In addition, after you handle the exception, you set context.Exception to null in order to avoid further handling.
To achieve this in your code, you need to replace your comment from MethodExceptionFilterAttribute with context.Exception = null to clear the exception.
It is important to note that it is not a good idea to register more than one global exception filter, due to ordering issues. For information about the execution order of attribute filters in Web API, see the following thread Order of execution with multiple filters in web api.

How can I use the AsyncCTP with an TFS APM Method (Query.Begin/EndQuery)?

Would like to try using AsyncCTP with TFS. Currently have a long running method that calls RunQuery on a TFS Query instance.
Query exposes the APM methods BeginQuery() and EndQuery(). As I understand it, the recommended approach to wrap these using AsyncCTP is something like: (example from docs)
Task<int>.Factory.FromAsync(stream.BeginRead, stream.EndRead, buffer, offset, count, null);
Further, have wrapped it in an extension method as in the docs so my actual method looks like:
public static Task<WorkItemCollection> RunQueryAsync(this Query query)
{
if (query== null)
throw new ArgumentNullException("Query");
return Task<WorkItemCollection>.Factory.FromAsync(query.BeginQuery, query.EndQuery, null);
}
...but this fails to compile. Getting an "invalid argument" intellisense error that, frankly, I can't really understand because the types and format look correct. One possible issue might be that the Query APM methods expect an ICanceleableAsyncResult whereas the Task factory is expecting an IAsyncResult -- but looking at the TFS API, ICanceleableAsyncResult is a specialization of IAsyncResult.
Not sure whether i'm doing it wrong or its just not possible. Would love to be able to do it the AsyncCTP way but may have to go back to the APM pattern -- ugh!
Update: My Nito.AsyncEx library now includes a TeamFoundationClientAsyncFactory type, which can be used instead of rolling your own implementation below.
The TFS API is not strictly following the APM pattern because it does not take a state parameter, and this is preventing the built-in TaskFactory.FromAsync from working.
You'll have to write your own FromAsync equivalent, which can be done using TaskCompletionSource:
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.TeamFoundation.Client;
public static class TfsUtils<TResult>
{
public static Task<TResult> FromTfsApm(Func<AsyncCallback, ICancelableAsyncResult> beginMethod, Func<ICancelableAsyncResult, TResult> endMethod, CancellationToken token)
{
// Represent the asynchronous operation by a manually-controlled task.
TaskCompletionSource<TResult> tcs = new TaskCompletionSource<TResult>();
try
{
// Begin the TFS asynchronous operation.
var asyncResult = beginMethod(Callback(endMethod, tcs));
// If our CancellationToken is signalled, cancel the TFS operation.
token.Register(asyncResult.Cancel, false);
}
catch (Exception ex)
{
// If there is any error starting the TFS operation, pass it to the task.
tcs.TrySetException(ex);
}
// Return the manually-controlled task.
return tcs.Task;
}
private static AsyncCallback Callback(Func<ICancelableAsyncResult, TResult> endMethod, TaskCompletionSource<TResult> tcs)
{
// This delegate will be invoked when the TFS operation completes.
return asyncResult =>
{
var cancelableAsyncResult = (ICancelableAsyncResult)asyncResult;
// First check if we were canceled, and cancel our task if we were.
if (cancelableAsyncResult.IsCanceled)
tcs.TrySetCanceled();
else
{
try
{
// Call the TFS End* method to get the result, and place it in the task.
tcs.TrySetResult(endMethod(cancelableAsyncResult));
}
catch (Exception ex)
{
// Place the TFS operation error in the task.
tcs.TrySetException(ex);
}
}
};
}
}
You can then use it in extension methods as such:
using System.Threading;
using System.Threading.Tasks;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
public static class TfsExtensions
{
public static Task<WorkItemCollection> QueryAsync(this Query query, CancellationToken token = new CancellationToken())
{
return TfsUtils<WorkItemCollection>.FromTfsApm(query.BeginQuery, query.EndQuery, token);
}
}

Building a single entry point to a WCF service: need unified approach to return objects and collections

Subject says it all: I'm creating a secure and generic wrapper to access a WCF service transparently.
A little background:
what I have done is that I've created similar business classes definition both on server and client. The server-side contains the actual logic while the client side contains only method definitions. Additionally, the client-side classes derive from a SecureFactory which implements a Call method. The body of every method of each derived class contains only a call to Call method. This Call method is responsible for invoking the server service passing such things as to the type of business class and which of its method to invoke to perform the requested operation.
This approach is being designed in order to simplify security checks by restricting passing of security information to only between SecureFactory and Server service. There are tuns of other benefits which you most of already aware of.
Now here's the issue: I'm stuck at as to how to return objects (especially arrays of objects) from Server to Call method?
The server may return a single business object (DataContract applied) as well as list of such objects. Since it's a generic approach, I have only Object to be used as return type. Following is the Call method
public object Call(params object[] parameters)
{
var mb = (new StackFrame(1).GetMethod());
using (Proxy.ServerClient server = new Security.BO.Proxy.ServerClient())
{
try
{
if (((MethodInfo)mb).ReturnType.IsGenericType)
{
var response = server.InvokeForList(SecurityManager.Current.SID, SecurityManager.Current.Token, mb.DeclaringType.ToString(), mb.Name, parameters);
return response.Result.ToList();
}
else
{
var response = server.Invoke(SecurityManager.Current.SID, SecurityManager.Current.Token, mb.DeclaringType.ToString(), mb.Name, parameters);
return response.Result;
}
}
catch (Exception ex)
{
System.Diagnostics.Debugger.Break();
}
}
return null;
}
server methods:
public CollectionResponse InvokeForList(string SID, string token, string type, string method, object[] parameters)
{
// Validation here
var t = assemblyBO.GetType(type, true);
object BO = Activator.CreateInstance(t);
var mi = t.GetMethod(method);
if (mi == null)
throw new MethodNotImplementedException("Method " + method + " could not be found on type " + t.ToString());
object res = mi.Invoke(BO, parameters);
// Convert list to t[]
object list = res.GetType().GetMethod("ToArray").Invoke(res, new object[0]);
// Error here! cannot convert t[] into object[]
return new CollectionResponse((object[])list);
}
The other method Invoke(...) is similar accept it returns Response object instead of CollectionResponse.
Here's the CollectionResponse class: (Response is similar:just it takes only one object)
[DataContract]
public class CollectionResponse
{
[DataMember]
private Object[] _result;
public Object[] Result
{
get
{
return _result;
}
}
public CollectionResponse(Object[] result)
{
this._result = result;
}
}
Initially I was thinking to have only one Invoke for both lists and singleton – but failed with "Connection was closed unexpectedly." still I'm not able to achieve – how can I convert T[] into object[].
Do you have any suggestion to improve it, or any other way of achieving the same?
Thanks
I can see an immediate problem here. You are using reflection which is far less perfromant than the direct call.
For me, that is enough not to follow this route.

Resources