How to get the local context injected in an Eclipse 4 command handler - eclipse-plugin

I want to wrap/decorate another Eclipse 4 command handler. To that effect, my handler has #CanExecute and #Execute methods which invoke the wrapped handler's respective #CanExecute and #Execute methods using ContextInjectionFactory.invoke like so:
#Execute
public void execute(IEclipseContext context) {
// Decorator functionality goes here
IEclipseContext localContext = null; // How to obtain this?
ContextInjectionFactory.invoke(decoratee, Execute.class, context, localContext, null));
}
Unfortunately, this looses any "local context" the ContextInjectionFactory invoking the wrapper might have had.
The only way to obtain this local context is using an internal API (org.eclipse.e4.core.internal.contexts.ContextObjectSupplier):
#Execute
public void execute(IEclipseContext context, ContextObjectSupplier localContextSupplier) {
// Decorator functionality goes here
IEclipseContext localContext = localContextSupplier.getContext(); // internal API :-(
ContextInjectionFactory.invoke(decoratee, Execute.class, context, localContext, null));
}
Is there a way to achieve the same goal, i.e., transparently wrapping an Eclipse 4 command handler that does not require resorting to internal API?

Related

How to test with Response.OnCompleted delegate in a finally block

I have the following netcore 2.2 controller method that I am trying to write an xUnit integration test for:
private readonly ISoapSvc _soapSvc;
private readonly IRepositorySvc _repositorySvc;
public SnowConnectorController(ISoapSvc soapSvc, IRepositorySvc repositorySvc)
{
_soapSvc = soapSvc;
_repositorySvc = repositorySvc;
}
[Route("accept")]
[HttpPost]
[Produces("text/xml")]
public async Task<IActionResult> Accept([FromBody] XDocument soapRequest)
{
try
{
var response = new CreateRes
{
Body = new Body
{
Response = new Response
{
Status = "Accepted"
}
}
};
return Ok(response);
}
finally
{
// After the first API call completes
Response.OnCompleted(async () =>
{
// Run the close method
await Close(soapRequest);
});
}
}
The catch block runs and does the things it needs to, then the finally block runs and does things it needs to do after the request in the catch finishes per design.
Close has been both a private method . It started as a public controller method but I don't need to expose it for function so moved it to private method status.
Here's an integration test I started with the intention of just testing the try portion of the code:
[Fact]
public async Task AlwaysReturnAcceptedResponse()
{
// Arrange------
// Build mocks so that we can inject them in our system under tests constructor
var mockSoapSvc = new Mock<ISoapSvc>();
var mockRepositorySvc = new Mock<IRepositorySvc>();
// Build system under test(sut)
var sut = new SnowConnectorController(mockSoapSvc.Object, mockRepositorySvc.Object);
var mockRequest = XDocument.Load("..\\..\\..\\mockRequest.xml");
// Act------
// Form and send test request to test system
var actualResult = await sut.Accept(mockRequest);
var actualValue = actualResult.GetType().GetProperty("Value").GetValue(actualResult);
// Assert------
// The returned object from the method call should be of type CreateRes
Assert.IsType<CreateRes>(actualValue);
}
I am super new to testing... I've been writing the test and feeling my way through the problem. I started by entering the controller method not really knowing where it would go. The test works through the try method, and then an exception is thrown once it hits the delegate in the finally block.
It looks like my test will have to run through to the results of the finally block unless there is a way to tell it to stop with the catch blocks execution?
That's fine, i'm learning, but the problem with that approach for me now is that the HttpResponse's Response.OnCompleted delegate in the finally block returns null when my test is running and I haven't been successful at figuring out what I can do to not make it null - because it is null, it throws this when my unit test is executing -
System.NullReferenceException: 'Object reference not set to an instance of an object.'
*One thought that occurred was that if I was to make the private Close method a public controller method, and then make the Accept method not have the finally block, I could create a third controller method that does the try finally action by running the two controller methods and then just test the individual controller methods that are strung together with the third. However, it doesn't feel right because I would be exposing methods just for the sake of unit testing and I don't need Close to be exposed.
If the above idea is not the right approach, I am wondering what is, and if I just need to test through end to end, how I would get over the null httpresponse?
Any ideas would be appreciated. Thank you, SO community!
EDIT - Updated Test that works after the accepted answer was implemented. Thanks!
[Fact]
public async Task AlwaysReturnAcceptedResponse()
{
// Arrange------
// Build mocks so that we can inject them in our system under tests constructor
var mockSoapSvc = new Mock<ISoapSvc>();
var mockRepositorySvc = new Mock<IRepositorySvc>();
// Build system under test(sut)
var sut = new SnowConnectorController(mockSoapSvc.Object, mockRepositorySvc.Object)
{
// Supply mocked ControllerContext and HttpContext so that finally block doesnt fail test
ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext()
}
};
var mockRequest = XDocument.Load("..\\..\\..\\mockRequest.xml");
// Act------
// Form and send test request to test system
var actualResult = await sut.Accept(mockRequest);
var actualValue = actualResult.GetType().GetProperty("Value").GetValue(actualResult);
// Assert------
// The returned object from the method call should be of type CreateRes
Assert.IsType<CreateRes>(actualValue);
}
Curious what you are doing in the Close method against the input parameter.
Does it have to happen after response is being sent? It might not always happen as you would expect, see here.
Regardless though, during runtime asp.net core runtime sets a lot of properties on the controller including ControllerContext, HttpContext, Request, Response etc.
But those won't be available in unit testing since there is no asp.net core runtime there.
If you really want to test this, you'll have to mock them.
Here is the ControllerBase source code.
As we can see, ControllerBase.Response simply returns ControllerBase.HttpContext.Response, and ControllerBase.HttpContext is a getter from ControllerBase.ControllerContext. This means you'll have to mock a ControllerContext (and the nested HttpContext as well as HttpResponse) and assign it to your controller in the setup phase.
Furthermore, the OnCompleted callback won't get called in unit test either. If you want to unit test that part, you'll have to trigger it manually.
Personally I think it's too much hassle beside the open bug I mentioned above.
I would suggest you move the closing logic (if it's really necessary) to a IDisposable scoped service and handle that in the Dispose instead - assuming it's not a computation heavy operation which can impact the response latency.

How do i wireup NServiceBus' SqlSaga in a test scenario?

https://docs.particular.net/nservicebus/testing/ has a very neat example of how to test a simple Saga. Unfortunately it does not explain, how to do the same with a SqlSaga - ie. a Saga with persistence of state to a database.
Given this saga:
public class SomeFancySaga : SqlSaga<MySagaData>,
IAmStartedByMessages<ImportantCommand>
{
protected override string CorrelationPropertyName => nameof(Data.MyPrimaryKey);
protected override void ConfigureMapping(IMessagePropertyMapper mapper)
{
mapper.ConfigureMapping<ImportantCommand>(x => x.CommandId);
}
public async Task Handle(ImportantCommand command, IMessageHandlerContext context)
{
if (Data.State == MyState.ReadyForUse)
<do some stuff>
}
...
}
If I try to write test-code like the example in the link, I would do something like this:
// arrange
var context = new NServiceBus.Testing.TestableMessageHandlerContext();
var command = ImportantCommand.Create();
var sut = new CreateSomeFancySaga();
// act
sut.Handle(command, context);
// assert
...
The call to sut.Handle() will throw a NullReferenceException, because the Saga property Data has not been initialized.
How do I correctly wireup the saga for testing so that:
Data is initialized
A real database connection is not really needed
We have a related code sample showing unit testing in more detail: https://docs.particular.net/samples/unit-testing/. That includes a couple of tests for saga (SagaTests.cs).
You can take this as a starting point and modify the saga tests in the following way:
Add NServiceBus.Persistence.Sql package.
Modify the DiscountPolicy policy saga to inherit from SqlSaga instead of a Saga.
Resolve compilation errors (add missing method and property, you can keep them empty, plus remove the ConfigureHowToFindSaga method).
I hope that helps, but let me know if there's anything missing or your scenario can't be tested this way.

How to rollback nHibernate transaction when an exception occurs during request having Ninject for managing sessions?

I use nHibernate for ORM and Ninject for IoC.
I create nHibernate sessions per some custom scope (which you can assume is per request).
I begin the transaction onActivation.
I commit the transaction onDeactivation.
The problem is that if an exception happens during the request I want to rollback the transaction rather than committing it. Any idea how to detect (in a clean way, most probably using Ninject Context) that an exception has happened?
Note: I am not concerned about the exceptions that can happen on commit which I can catch in the following code and role back easily.
protected void BindWithSessionWrapper<T>(Func<IContext, T> creationFunc) where T : ISessionWrapper
{
Bind<T>().ToMethod(creationFunc)
.InScope(x => new NinjectCustomScope()) // work in progress !!!
.OnActivation(t => t.Session.BeginTransaction(IsolationLevel.ReadCommitted))
.OnDeactivation((c, t) =>
{
t.Session.Transaction.Commit();
t.Session.Dispose();
});
}
Update:
I followed the suggestion by #BatteryBackupUnit.
So I added the following to the Error EventHandler:
Error += (s, e) =>
{
HttpContext.Current.Items["ErrorRaised"] = true;
};
And I modified the OnDeactivation to look like this:
OnDeactivation(t =>
{
if ((bool?)HttpContext.Current.Items["ErrorRaised"] == true)
t.Session.Transaction.Rollback();
else
t.Session.Transaction.Commit();
t.Session.Dispose();
});
It works fine, but that would be better if Ninject would take care of this by setting a flag in the Context if an exception happened :)
How about implementing an IHTTPModule and subscribing to the Error event?
Like described here
In the Error event handler, use System.Web.Mvc.DependencyResolver.Current.GetService(typeof (ISession)) to retrieve the current session and rollback the transaction.
Note, however, that in case the request did not use a session, this will create one, which is quite superfluous.
You might do something like checking whether a transaction was started and only then rolling it back. But you'd still create a session unnecessarily.
You could further improve that by using the Error event handler to set a flag on HttpContext.Current.Items, like
HttpContext.Current.Items["RollbackTransaction"] = true;
and then use it in the OnDeactivation of the session like:
.OnDeactivation((c, t) =>
{
if(HttpContext.Current.Items.Contains("RollbackTransaction"])
{
t.Session.Transaction.Rollback();
}
else
{
t.Session.Transaction.Commit();
}
t.Session.Dispose();
});
Please note that HttpContext is thread local, that means when you switch threads it may be null or -worst case - it might even be another HttpContext.
Please also note that i was unable to try it out so it may not work. Feedback appreciated.
Passing the state through HttpContext is not acceptable to me for 2 reasons.
HttpContext issue: https://stackoverflow.com/a/12219078/656430)
Passing state seems like passing a global state (https://softwareengineering.stackexchange.com/questions/148108/why-is-global-state-so-evil)
After a lot of trial and error, I think this should be one solution:
Assuming we are working on WebApi project, having rollback transaction for all actions once hit exception, with Ninject:
install Ninject.Extension.Factory (https://www.nuget.org/packages/Ninject.Extensions.Factory/), this is very important step as to inject ISession in request scope into filters.
use the following configuration for binding ISessionFactory and ISession (I made use of this example: Need a simple example of using nhibernate + unit of work + repository pattern + service layer + ninject), plus ISessionInRequestScopeFactory
Bind<ISessionFactory>().ToProvider<NhibernateSessionFactoryProvider>().InSingletonScope();
Bind<ISession>()
.ToMethod(context => context.Kernel.Get<ISessionFactory>().OpenSession())
.InRequestScope(); // notice that we don't need to call `BeginTransaction` at this moment
Bind<ISessionInRequestScopeFactory>().ToFactory(); // you don't need to make your implementation, the Ninject.Extension.Factory extension will help you so.
the code for interface ISessionInRequestScopeFactory:
public interface ISessionInRequestScopeFactory
{
ISession CreateSessionInRequestScope(); // return ISession in the request scope
}
Make use of ninject filter injection to add Transaction behaviour to every action (https://github.com/ninject/Ninject.Web.WebApi/wiki/Dependency-injection-for-filters):
Kernel.BindHttpFilter<ApiTransactionFilter>(System.Web.Http.Filters.FilterScope.Action)
.WhenControllerHas<ApiTransactionAttribute>();
add [ApiTransaction] attribute into controller:
[ApiTransaction]
public class YourApiController{ /* ... */}
So we are now binding the ApiTransactionFilter into YourApiController which are having [ApiTransaction] Attribute
Inside ApiTransactionFilter, you should extends AbstractActionFilter and inject the factory ISessionInRequestScopeFactory for getting the correct request scope session:
public class ApiTransactionFilter : AbstractActionFilter{
private readonly ISessionInRequestScopeFactory factory;
public ApiTransactionFilter(ISessionInRequestScopeFactory factory){
this.factory = factory;
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
ISession session = factory.CreateSessionInRequestScope(); // get the request scope session through factory
session.BeginTransaction(); // session can begin transaction here ...
base.OnActionExecuting(actionContext);
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
ISession session = factory.CreateSessionInRequestScope(); // get the request scope session through factory
if (actionExecutedContext.Exception == null) // NO EXCEPTION!
{
session.Transaction.Commit();// session commit here ... may be you like to have try catch here
}
else
{
session.Transaction.Rollback(); // session rollback here ...
}
base.OnActionExecuted(actionExecutedContext);
}
}

async method does not continue when await statement returns

I'm using MVC 4 and I have the following code :
public void DoWork(string connectionId)
{
connectionId = this.connectionId;
var a = MakeADelayAsync();
}
public async Task MakeADelayAsync()
{
await Task.Delay(5000);
var generalHubContext = GlobalHost.ConnectionManager.GetHubContext<GeneralHub>();
generalHubContext.Clients.Client(connectionId).showNotification("Completed");
}
"DoWork" method is my mvc action. what I intent to do is when the action button is pressed the "DoWork" calls an async method and returns to the client immediately. when the async method has completed his job it will notify client using signalR.
The problem is in the "MakeADelayAsync" method, those two lines after await won't be called ever. It seems that the flow never continues after await.
First question is Where is the problem in "MakeADelayAsync" ?
Second question is why do I have to write a useless code of var a = MakeADelayAsync(); to avoid compiler warning while I'm completely aware of what I am doing? I never use "a" anyway.
"DoWork" method is my mvc action. what I intent to do is when the action button is pressed the "DoWork" calls an async method and returns to the client immediately. when the async method has completed his job it will notify client using signalR.
Doing this is extremely dangerous. I strongly recommend that you use a persistent queue, as I said in my previous answer: Azure queue, MSMQ, WebSphere MQ, etc.
However, if you insist on doing it the dangerous way, then you can use the code that I have on my blog to execute background work on ASP.NET outside of a request context:
public void DoWork(string connectionId)
{
connectionId = this.connectionId;
// This is extremely dangerous code! If ASP.NET unloads
// your app, then MakeADelayAsync may not run to completion.
BackgroundTaskManager.Run(() => MakeADelayAsync());
}
First question is Where is the problem in "MakeADelayAsync" ?
You're executing code that is attempting to resume on the request context after the request is completed and the request context is disposed. It's the same problem you had before.
Second question is why do I have to write a useless code of var a = MakeADelayAsync(); to avoid compiler warning while I'm completely aware of what I am doing?
The compiler warning is telling you that the code is almost certainly a mistake... and the compiler is right.
can you try to mark your DoWork method as async?
public async void DoWork(string connectionId)
{
connectionId = this.connectionId;
var a = MakeADelayAsync();
}

Async End<Method> not called in WCF

I have the following situation: My WCF service allows a client to register to wait for some event. The waiting is asynchronous on the service side, that is, the waiter is registered and when the process is finished, the waiter is notified. At the moment, it's simply a ManualResetEvent.
Now I want to expose this method via WCF. I tried to use AsyncPattern=true and created two methods, BeginWait which bundles the event into a IAsyncResult, and EndWait which calls AsyncWaitHandle.WaitOne(). However, if I call BeginWait, EndWait from the client, the server side EndWait is not executed. I'm using a manually implemented wrapper (my proxy class is derived from ChannelBase<IWaitService>, IWaitService), which basically calls Channel.EndWait(), and this function is indeed called; but on the server side, the call never arrives.
What am I doing wrong here? Follow-up question: If the asynchronous call is working, is there an easy way to make that synchronous on the client side?
The line
var task = Task.Factory.StartNew(() => IsPrime(a));
uses overload
TaskFactory.StartNew(Action)
which results in
((IAsyncResult)task).AsyncState == null
the call to callback(task) results in an ArgumentException, complaining that the state object is different from the state object that was passed to the BeginXxx method. The line must be modified to
var task = Task.Factory.StartNew((actionState) => IsPrime(a), state);
using overload
TaskFactory.StartNew(Action<object>, object)
such that the state object passed by WCF ends up in the task:
((IAsyncResult)task).AsyncState.GetType().FullName == System.ServiceModel.Dispatcher.MessageRpc+Wrapper
The synchronous/asynchronous decision can be made independently on the server or client side. Calling EndWait on the client does not translate into an EndWait call on the server. I would recommend testing an async service with a sync client just to keep things simple and avoid confusion.
I would further recommend that you not call WaitOne inside of the EndWait method. The contract is that this method will only be called after the IAsyncResult tells the framework that it is done. This is done in one of three ways:
CompletedSynchronously returns true
The AsyncCallback is invoked
The AsyncWaitHandle is signalled
CompletedSynchronously should only return true if BeginWait had enough information to complete the request before it returned. This is probably not the case. You can satisfy the other two conditions with your ManualResetEvent as follows:
class EventBasedAsyncResult : IAsyncResult
{
private readonly ManualResetEvent _manualResetEvent;
private readonly AsyncCallback _asyncCallback;
private readonly object _asyncState;
public EventBasedAsyncResult(AsyncCallback callback, object asyncState)
{
_manualResetEvent = new ManualResetEvent(false);
_asyncState = asyncState;
_asyncCallback = callback;
}
public void WaitCompleted()
{
_manualResetEvent.Set();
_asyncCallback(this);
}
public object AsyncState
{
get { return _asyncState; }
}
public WaitHandle AsyncWaitHandle
{
get { return _manualResetEvent; }
}
public bool CompletedSynchronously
{
get { return false; }
}
public bool IsCompleted
{
get { return _manualResetEvent.WaitOne(0); }
}
}
I think once you do this you'll find that EndWait is called, even if the client is synchronous.