running wf workflow from mvc controller - model-view-controller

enter code hereI intend to use WF4.5 in a web application which is written by MVC Framework. I have used WorkflowApplication class instance to run my WorkFlow with. but whenever i call the method in controller that run the instance I get this error:
An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%# Page Async="true" %>. This exception may also indicate an attempt to call an "async void" method, which is generally unsupported within ASP.NET request processing. Instead, the asynchronous method should return a Task, and the caller should await it
I have written this class which is resposnsible to execute workflow:
public class WorkFlowsPipeline : IWorkFlowsPipeline
{
private IUnitOfWork _unitOfWork;
private SqlWorkflowInstanceStore _instanceStore;
public WorkFlowsPipeline(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
//workflowInstanceStore
_instanceStore = new SqlWorkflowInstanceStore();
_instanceStore.ConnectionString ="data source=.;initial catalog=WFPersist;user id=sa;password=1;";
}
public void RecordPersistedInstanceForTheUser(int userId,Guid instanceId, Models.Enums.WorkFlowTypeEnum workFlowType)
{
_unitOfWork.UsersWorkFlows.Add(new UsersWorkFlowsInstance
{
UserId = userId,
WorkFlowId=instanceId,
WorkFlowType = workFlowType
});
}
public void RunCompleteProfileForUser(int userId)
{
var usersWorkFlow = _unitOfWork.UsersWorkFlows.GetAll().FirstOrDefault(x => x.UserId == userId);
if (usersWorkFlow == null)
{
Activity rentalWorkflow = new Activity1();
Dictionary<string, object> wfArg = new Dictionary<string, object>()
{
{
"UOW", _unitOfWork
},
{
"UserId",userId
}
};
var _wfApp = new WorkflowApplication(rentalWorkflow, wfArg);
_wfApp.SynchronizationContext = SynchronizationContext.Current;
_wfApp.InstanceStore = _instanceStore;
//_wfApp.Extensions.Add(this);
var instanceId=_wfApp.Id;
_wfApp.Run();
RecordPersistedInstanceForTheUser(userId, instanceId,WorkFlowTypeEnum.CompleteProfile);
}
else
{
//get id of instance load it from database and run it
}
}
}
and I called the method in my controller action in this way:
public async Task<ActionResult> Index()
{
var userId = User.Identity.GetUserId<int>();
_workFlowsPipeline.RunCompleteProfileForUser(userId);
return View();
}

Use WorkflowInvoker instead of WorkflowApplication.

Related

Xamarin Forms with WorkManger

I am trying to use the Xamarin implementation of WorkManager, in the nuget package Xamarin.Android.Arch.Work.Runtime.
The questions is: how to pass "complex" parameters to the worker class?
I have a Xamarin Forms application with DI and others classes, but the job only receives a Java.Lang.Object.
My code:
// Method to Schedule the Job
// See the dataParam? That line throw an exception
// I can manage to pass a simple string or int to the job this way, but not
// complex classes
public void ScheduleAppJobs(IContainerProvider containerRegistry)
{
//here the code throw an exception
var dataParam = new Data.Builder().Put("param", new JobParameter());
var syncWorkerReuest = PeriodicWorkRequest.Builder.From<SyncChecklistWorker>(TimeSpan.FromMinutes(5))
.SetInputData(dataParam.Build())
.Build();
WorkManager.Instance.Enqueue(syncWorkerReuest);
}
//this was my try to create a custom class and populate with my objects
//But didn't worked
public class JobParameter : Java.Lang.Object
{
}
//my job implementation
public class SyncChecklistWorker : Worker
{
public SyncChecklistWorker(Context context, WorkerParameters workerParameters) : base(context, workerParameters)
{
}
public override Result DoWork()
{
if (InputData.KeyValueMap.TryGetValue("param", out Java.Lang.Object #object))
{
var jobParam = (JobParameter)#object;
// here I would like to get my DI container to resolve services and execute business logic
// var diResolver = jobParam.GetDIContainer();
return Result.InvokeSuccess();
}
return Result.InvokeRetry();
}
}
}
The problem is:
The only way to pass input data to a jobs the Data.Builder only accepts Java.Lang.Object. Even trying to approach of having JobParameter : Java.Lang.Object I get the following error when trying to execute the: new Data.Builder().Put("param", new JobParameter()); Error: Java.Lang.IllegalArgumentException: 'Key param has invalid type class crc648d221dddf00bc7fb.JobParameter'
On the official Microsoft Docs the FireBase Job Dispatcher nuget is deprecated. So how to work with the new WorkManager one?
FireBase Job Dispatcher Doc:
https://learn.microsoft.com/en-us/xamarin/android/platform/firebase-job-dispatcher
Deprecated nuget:
https://www.nuget.org/packages/Xamarin.Firebase.JobDispatcher
Any idea of how to solve this?
Work request from Data builder accepts only the premitive types. You can pass the object by serializing to JSON string format and in DoWork() you can deserialize it.
public void ScheduleAppJobs(IContainerProvider containerRegistry)
{
var dataParam = new Data.Builder().PutString("param",serializeToJson(new
MyClass()));
var syncWorkerReuest = PeriodicWorkRequest.Builder.From<SyncChecklistWorker>
(TimeSpan.FromMinutes(5))
.SetInputData(dataParam.Build())
.Build();
WorkManager.Instance.Enqueue(syncWorkerReuest);
}
public override Result DoWork()
{
var jsonString = InputData.GetString("param");
var myClassObj = deserializeFromJson(jsonString );
}
using Newtonsoft.Json;
public string serializeToJson(MyClass myClassObj)
{
var resultString = JsonConvert.SerializeObject(myClassObj);
return resultString;
}
// Deserialize to single object.
public MyClass deserializeFromJson(string jsonString)
{
var serializer = new JsonSerializer();
var resultObject = serializer.Deserialize<MyClass>(jsonString);
}

Entity Framework 6 "DbContext has been disposed" exception

Something very strange is happening in production, and it only happens in production. I have a Web API running and in one of the APIs, there is a repository created in the constructor and used in the functions. This is how the flow of a request works:
HTTP request comes in
MVC API controller decides which "worker" class to instantiate and creates it using Activator.CreateInstance
API controller calls worker.OnExecute inside of a Task.Run() and returns the http response
Worker calls _engine.Execute
Each worker instantiates another "engine" class that has all of the logic.
The engine in case constructs 3 repositories created using a UnitOfWork that is created per engine instance, like so:
public class MyWorker : Worker
{
private readonly MyEngine _engine;
public MyWorker()
{
_engine = new MyEngine();
}
protected override WorkerResult OnExecute(JObject data, CancellationToken cta)
{
return new WorkerResult(HttpStatusCode.OK, _engine.Execute(data));
}
}
public class MyEngine : EngineBase
{
private BaseRepository<Order> OrderRepo { get; set; }
private BaseRepository<OrderItem> OrderItemRepo { get; set; }
public MyEngine()
{
OrderRepo = new BaseRepository<Order>(MyUnitOfWork);
OrderItemRepo = new BaseRepository<OrderItem>(MyUnitOfWork);
}
public string Execute(JObject data)
{
return IsOrderValid(data).ToString();
}
public bool IsOrderValid(JObject data)
{
var orderId = data.Value<int>("OrderId");
// Without this line it crashes. With this line it crashes
//OrderRepo = new BaseRepository<Order>(InternationalWork);
// This is where it crashes
Order order = OrderRepo.First(x => x.OrderID == orderId);
// more code
}
}
public class EngineBase : UnitOfWorker, IDisposable
{
private UnitOfWork _myUnitOfWork;
public EngineBase() { }
public UnitOfWork MyUnitOfWork
{
get
{
return _myUnitOfWork ?? (_myUnitOfWork = new UnitOfWork(new DbContextAdapter(new MyDbContext())));
}
}
}
This is the actual stack trace:
The operation cannot be completed because the DbContext has been disposed.
StackTrace1
at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
at System.Data.Entity.Internal.LazyInternalContext.get_ObjectContext()
at System.Data.Entity.Internal.Linq.InternalSet`1.CreateObjectQuery(Boolean asNoTracking, Nullable`1 streaming, IDbExecutionStrategy executionStrategy)
at System.Data.Entity.Internal.Linq.InternalSet`1.InitializeUnderlyingTypes(EntitySetTypePair pair)
at System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext()
at System.Data.Entity.Infrastructure.DbQuery`1.System.Linq.IQueryable.get_Provider()
at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source, Expression`1 predicate)
The stack trace shows "FirstOrDefault" because OrderRepo.First internally calls DbSet.FirstOrDefault, like so:
public virtual T First(Expression<Func<T, bool>> query)
{
return _dbSet.FirstOrDefault(query);
}
I'm stumped because each worker is created per http request. Each DBContext is created per engine instance so I don't know how it could be disposed when it was just created in the constructor. And this only happens on the production web server where I presume it's being called more. Any tips would be greatly appreciated.

How to write test code for Web API in Visual Studio?

I'm a bit new to test project. I currently have a web api project which contains Get, Put, Post and Delete methods. When comes to writing test cases, I'm confused. Should I write test code to test the Http URL?
My web api code:
// GET api/values/5
[HttpGet("{id}")]
public IActionResult Get(string id)
{
using (var unitOfWork = new UnitOfWork(_db))
{
var r = unitOfWork.Resources.Get(id);
unitOfWork.Complete();
Models.resource result = ConvertResourceFromCoreToApi(r);
if (result == null)
{
return NotFound();
}
else
{
return Ok(result);
}
}
}
And in my test project, I kind of stuck here. We are using Xunit. How to write test code to test the Get method? Or should I write code to test the URL api/values/5 instead, but how?
[Fact]
public void GetTest()
{
using (var unitOfWork = new UnitOfWork(new MockDatabase()))
{
}
}
Any help would be appreciated.
You need to make a couple of changes before you can really unit test your controller. You need to pass an instance of your UnitOfWork class into the controller in its constructor. Then your controller method code becomes:
// GET api/values/5
[HttpGet("{id}")]
public IActionResult Get(string id)
{
var r = unitOfWork.Resources.Get(id);
unitOfWork.Complete();
Models.resource result = ConvertResourceFromCoreToApi(r);
if (result == null)
{
return NotFound();
}
else
{
return Ok(result);
}
Then in your unit tests you do this:
[Fact]
public void GetTest()
{
// Arrange
// You really want to mock your unit of work so you can determine
// what you are going to send back
var unitOfWork = new MockUnitOfWork();
var systemUnderTest = new Controller(unitOfWork);
system.Request = new HttpRequestMessage();
// Act
var result = systemUnderTest.Get(1);
// Assert
// Here you need to verify that you got back the expected result
}
Injecting the UnitOfWork class into the controller is probably another question. Mark Seemann has an excellent post on the subject, but it might be a little advanced. There are a number of different ways to accomplish that with simpler (but maybe not as robust methods). Google is your friend with that. But if you have questions, post another question.
Hope that helps.
You would need to make some design changes to your controller to make it easy to test. In your action you are creating an instances which will make it difficult to test with a fake dependencies to the controller. Also your controller should depend on abstractions rather than concretions which will allow the controller to be more testable.
public class MyWebApiController : ApiController {
private IUnitOfWork unitOfWork;
public MyWebApiController(IUnitOfWork unitOfWork) {
this.unitOfWork = unitOfWork;
}
// GET api/values/5
[HttpGet("{id}")]
public IActionResult Get(string id) {
var r = unitOfWork.Resources.Get(id);
unitOfWork.Complete();
Models.resource result = ConvertResourceFromCoreToApi(r);
if (result == null) {
return NotFound();
} else {
return Ok(result);
}
}
//...other code
}
Notice the controller uses dependency injection to inject an IUnitOfWork. That makes the controller more testable, because you can inject mocks of its dependencies when unit testing.
From there it is just to create an instance of the controller and call the method under test with mocks of the dependencies.
[Fact]
public void GetTest() {
//Arrange (Setup the parts needed to run test)
var unitOfWork = new MockUnitOfWork(new MockDatabase());
//Or using your mocking framework of choice
//var unitOfWork = Mock.Of<IUnitOfWork>(); //this is using Moq
var controller = new MyWebApiController(unitOfWork);
var id = "Test Id value here";
//Act (call the method under test)
var result - controller.Get(id);
//Assert (check results)
//...Do your assertion pertaining to result of calling method under test
}
Reference : Unit Testing Controllers in ASP.NET Web API 2

Custom route constraint causes intermittent 404 errors

I have an Asp.Net Core 1 RC1 application that uses a custom route constraint to control access to the application. The application (hosted on a server running IIS 7.5) is getting intermittent 404 errors which I suspect is caused by this routing constraint. Here you can see a screenshot that shows the intermittent 404 errors:
I suspect that this issue is related to the code that defines the route constraint not being thread-safe. The custom route constraint needs a DbContext because it needs to check in the database if the application is enabled for the brand specified in the route, and I suspect that this DbContext instance could be causing the issue. Here is how the routing is defined in the application:
// Add MVC to the request pipeline.
var appDbContext = app.ApplicationServices.GetRequiredService<AppDbContext>();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "branding",
template: "branding/{brand}/{controller}/{action}/{id?}",
defaults: new { controller="Home", action="Index" },
constraints: new { brand = new BrandingRouteConstraint(appDbContext) });
});
And here is the custom route constraint:
// Custom route constraint
public class BrandingRouteConstraint : IRouteConstraint
{
AppDbContext _appDbContext;
public BrandingRouteConstraint(AppDbContext appDbContext) : base() {
_appDbContext = appDbContext;
}
public bool Match(HttpContext httpContext, IRouter route, string routeKey, IDictionary<string, object> values, RouteDirection routeDirection)
{
if (values.Keys.Contains(routeKey))
{
var whiteLabel = _appDbContext.WhiteLabels.Where(w => w.Url == values[routeKey].ToString()).FirstOrDefault();
if (whiteLabel != null && whiteLabel.EnableApplication != null && (bool)whiteLabel.EnableApplication)
{
return true;
}
}
return false;
}
}
Can anyone confirm that this issue is caused by the code not being thread-safe and recommend a way to change the implementation so that it is thread-safe?
I can't comment on RouteContraint's, haven't used them much, but have you tried Resource Based Authorization instead? Looks like it might be more suited to what you're trying to achieve?
From here and here:
Request authentication service inside your controller
public class DocumentController : Controller
{
IAuthorizationService authorizationService;
public DocumentController(IAuthorizationService authorizationService)
{
this.authorizationService = authorizationService;
}
}
Apply authorization checks in your Action:
public async Task<IActionResult> Edit(Guid documentId)
{
Document document = documentRepository.Find(documentId);
if (document == null)
{
return new HttpNotFoundResult();
}
if (await authorizationService.AuthorizeAsync(User, document, Operations.Edit))
{
return View(document);
}
else
{
return new HttpUnauthorizedResult();
}
}
I've used the OperationAuthorizationRequirement class in the sample, so define this class in your project:
public static class Operations
{
public static OperationAuthorizationRequirement Create =
new OperationAuthorizationRequirement { Name = "Create" };
public static OperationAuthorizationRequirement Read =
new OperationAuthorizationRequirement { Name = "Read" };
public static OperationAuthorizationRequirement Update =
new OperationAuthorizationRequirement { Name = "Update" };
public static OperationAuthorizationRequirement Delete =
new OperationAuthorizationRequirement { Name = "Delete" };
}
Implement the authorization handler (using built in OperationAuthorizationRequirement requirement):
public class DocumentAuthorizationHandler : AuthorizationHandler<OperationAuthorizationRequirement, Document>
{
protected override void Handle(AuthorizationContext context,
OperationAuthorizationRequirement requirement,
Document resource)
{
// Validate the requirement against the resource and identity.
// Sample just checks "Name"field, put your real logic here :)
if (resource.Name == "Doc1")
context.Succeed(requirement);
else
context.Fail();
}
}
And not forgetting ConfigureServices:
services.AddInstance<IAuthorizationHandler>(
new DocumentAuthorizationHandler());
It's a bit more work, but adds quite a lot of flexibility.

How can I unit test an AuthorizeWhereIn attribute with Ninject

I'm using a custom authorisation attribute (blatantly plagiarised from another SO answer) but have hit a hurdle where I can't find a way to unit test it. Unfortunately I do need to unit test is at the same time as I invoke my controller action so I'm trying to find a way to do the Ninject dependency injection in the unit test.
The AuthorizeWhereIn attribute is:
public class AuthorizeWhereIn : AuthorizeAttribute
{
/// <summary>
/// Add the allowed roles to this property.
/// </summary>
public new HCIRoles Roles;
/// <summary>
/// Checks to see if the user is authenticated and has the
/// correct role to access a particular view.
/// </summary>
/// <param name="httpContext"></param>
/// <returns></returns>
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null)
throw new ArgumentNullException("httpContext");
// Make sure the user is authenticated.
if (!httpContext.User.Identity.IsAuthenticated)
return false;
// Get user's current roles
var roles = System.Web.Security.Roles.GetRolesForUser();
HCIRoles currentRoles = (HCIRoles)Enum.Parse(typeof(HCIRoles), string.Join(",", roles));
// Perform a bitwise operation to see if the user's role
// is in the passed in role values.
if (Roles != 0 && ((Roles & currentRoles) == 0))
return false;
return true;
}
}
The problem is the System.Web.Security.Roles.GetRolesForUser() call which isn't available in my unit test and which I want to mock any way. I can abstract that call into a separate interface and use Ninject to inject it for the web application but I can't find a way to do the same in a unit test.
So if I change the attribute to something like the below
public class AuthorizeWhereIn : AuthorizeAttribute
{
[Inject]
IRoleService RoleService { get; set; }
...
}
and my unit test code is along the lines of:
[TestMethod()]
public void IndexTest()
{
var builder = new TestControllerBuilder();
var controller = builder.CreateController<UserController>(dataLayer.Object);
var invoker = new ActionInvoker<UserController>();
var mockMembershipService = new Mock<IMembershipService>();
mockMembershipService.Setup(x => x.GetAllUsers(It.IsAny<int>(), It.IsAny<int>(), out total)).Returns(new MembershipUserCollection());
controller.MembershipService = mockMembershipService.Object;
builder.InitializeController(controller);
invoker.InvokeAction(controller.ControllerContext, x => x.Index());
}
And the controller being tested is:
[AuthorizeWhereIn(Roles = HCIRoles.Admin)]
public class UserController : BaseController
{
public ActionResult Index()
{
return View();
}
}
My question is how can I inject the RolseService depdency in the unit test given that I can't directly access the AuthroizeWhereIn attribute?
I've read and re-read the Ninject Filter extension for MVC3 http://www.planetgeek.ch/2010/11/13/official-ninject-mvc-extension-gets-support-for-mvc3/ but can't seem to apply it to this case.
given that I can't directly access the AuthroizeWhereIn attribute
Why not accessing it directly? That's what you are trying to test after all.
private class TestController : Controller { }
[TestMethod]
public void Test()
{
// arrange
var builder = new TestControllerBuilder();
var controller = new TestController();
builder.InitializeController(controller);
controller.ControllerContext = new ControllerContext(builder.HttpContext, new RouteData(), controller);
var httpContext = builder.HttpContext;
httpContext.Stub(x => x.Items).Return(new Hashtable());
var identity = new GenericIdentity("foo");
var roles = new string[0];
httpContext.User = new GenericPrincipal(identity, roles);
var ad = MockRepository.GeneratePartialMock<ActionDescriptor>();
var context = new AuthorizationContext(controller.ControllerContext, ad);
var sut = new AuthorizeWhereIn();
var service = MockRepository.GenerayeStub<IRoleService>();
sut.RoleService = service;
// TODO: set expectations on the service
// act
sut.OnAuthorization(context);
// assert
// TODO: assert on the type of context.Result
// If it is HttpUnauthorizedResult the authorization has failed
// (i.e. your custom AuthorizeCore method returned false)
}
A colleague ended up finding a clever solution using an extension method on IPrincipal. That way there's no need for dependency injection in the attribute since the HttpContext can be mocked with the Mvccontrib library.
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null)
throw new ArgumentNullException("httpContext");
// Make sure the user is authenticated.
if (!httpContext.User.Identity.IsAuthenticated)
return false;
// Get user's current roles
//var roles = System.Web.Security.Roles.GetRolesForUser();
HCIRoles currentRoles = httpContext.User.GetRoles();
// Perform a bitwise operation to see if the user's role
// is in the passed in role values.
if (Roles != 0 && ((Roles & currentRoles) == 0))
return false;
return true;
}
public static HCIRoles GetRoles(this IPrincipal user)
{
HCIRoles roles = 0;
foreach (HCIRoles r in Enum.GetValues(typeof(HCIRoles)))
{
if (user.IsInRole(r.ToString()))
roles |= r;
}
return roles;
}

Resources