If I use this code in each Repository class then I get SQL profiling to work but I want to move that code from each class into the class where StructureMap handles the DB.
Example of a Repository class:
public DB CreateNewContext()
{
var sqlConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["connection"].ConnectionString);
var profiledConnection = ProfiledDbConnection.Get(sqlConnection);
return DataContextUtils.CreateDataContext<DB>(profiledConnection);
}
public SqlRecipeRepository(DB dataContext)
{
_db = CreateNewContext();
}
Now I want the dataContext variable to be the profiled version and so come from my DBServiceRegistry class.
Here is the DBServiceRegistry class:
public class DBServiceRegistry : Registry
{
public DBServiceRegistry()
{
var sqlConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["GetMeCooking.Data.Properties.Settings.server"].ConnectionString);
var profiledConnection = ProfiledDbConnection.Get(sqlConnection);
For<DB>().HybridHttpOrThreadLocalScoped().Use(() => DataContextUtils.CreateDataContext<DB>(profiledConnection));
//Original method just had this:
//For<DB>().HybridHttpOrThreadLocalScoped().Use(() => new DB());
}
}
This code does not cause any errors but I don't get the SQL profiling, what am I doing wrong?
The comment is correct, by creating the sql connection outwith the For line, you are overriding the scope command.
Far better to encapsulate the whole lot into an anonymous delegate
using System.Configuration;
using System.Data.SqlClient;
using System.Threading.Tasks;
using StructureMap;
using StructureMap.Configuration.DSL;
using Xunit;
public class DBServiceRegistry : Registry
{
private string connString = ConfigurationManager.ConnectionStrings["GetMeCooking.Data.Properties.Settings.server"].ConnectionString;
public DBServiceRegistry()
{
For<DB>().HybridHttpOrThreadLocalScoped().Use(
() =>
{
var sqlConnection = new SqlConnection(connString);
var profiledConnection = new StackExchange.Profiling.Data.ProfiledDbConnection(sqlConnection, MiniProfiler.Current);
return DataContextUtils.CreateDataContext<DB>(profiledConnection);
});
}
}
You can use unit tests to verify that the scope is correct (test syntax is xunit.net)
public class DBRegistryTests : IDisposable
{
private Container container;
public DBRegistryTests()
{
// Arrange (or test setup)
container = new Container(new DBServiceRegistry());
}
[Fact]
public void ConnectionsAreSameInThread()
{
// Create two connections on same thread
var conn1 = container.GetInstance<DB>();
var conn2 = container.GetInstance<DB>();
// Assert should be equal because hybrid thread is scope
// and test executes on same thread
Assert.Equal(conn1, conn2);
// Other assertions that connection is profiled
}
[Fact]
public void ConnectionAreNotSameInDifferentThreads()
{
var conn1 = container.GetInstance<DB>();
// Request second connection from a different thread
// (for < c# 4.0 use Thread instead of task)
var conn2 = new Task<DB>(() => this.container.GetInstance<DB>());
conn2.Start();
conn2.Wait();
// Assert that request from two different threads
// are not the same
Assert.NotEqual(conn1, conn2.Result);
}
public void Dispose()
{
// Test teardown
container.Dispose();
}
}
Related
I have gotten a task that contains creating a .Net 4.8 application that contains a "HttpSelfHostServer".
I'm stuck in the quest of assigning "IServiceCollection services" to config.DependencyResolver (of type System.Web.Http.Dependencies.IDependencyResolver)
I would really like not to use autofac or other frameworks, but all guids I can find are pointing toward these frameworks. Isn't Microsoft providing a way through?
I just had to solve the same issue. This is how i did it:
First I created a new facade class to map the IServiceCollection from the host builder to the interface HttpSelfHostConfiguration supports:
using System;
using System.Collections.Generic;
using System.Web.Http.Dependencies;
using Microsoft.Extensions.DependencyInjection;
namespace IntegrationReceiver.WebApi
{
public class HttpSelfHostDependencyResolver : IDependencyResolver
{
private readonly IServiceProvider sp;
private readonly IServiceScope scope;
public HttpSelfHostDependencyResolver(IServiceProvider sp)
{
this.sp = sp;
this.scope = null;
}
public HttpSelfHostDependencyResolver(IServiceScope scope)
{
this.sp = scope.ServiceProvider;
this.scope = scope;
}
public IDependencyScope BeginScope() => new HttpSelfHostDependencyResolver(sp.CreateScope());
public void Dispose() => scope?.Dispose();
public object GetService(Type serviceType) => sp.GetService(serviceType);
public IEnumerable<object> GetServices(Type serviceType) => sp.GetServices(serviceType);
}
}
This required me to get the latest NuGet package Microsoft.Extensions.DependencyInjection.Abstractions according to an answer here: How do I see all services that a .NET IServiceProvider can provide?
I then registered my HttpSelfHostServer in the service provider with this code:
services.AddSingleton(sp => new HttpSelfHostDependencyResolver(sp));
services.AddSingleton(sp =>
{
//Starting the HttpSelfHostServer with user-level permissions requires to first run a command like
// netsh http add urlacl url=http://+:8080/ user=[DOMAINNAME]\[USERNAME]
var config = new HttpSelfHostConfiguration("http://localhost:8080");
config.Routes.MapHttpRoute("API Default", "api/{controller}/{id}", new { id = RouteParameter.Optional });
config.DependencyResolver = sp.GetRequiredService<HttpSelfHostDependencyResolver>();
return new HttpSelfHostServer(config);
});
And finally, to find my ApiController, I had to register that too in the service provider. I did that simply with:
services.AddScoped<HealthCheckController>();
For brewity, I'm just including my api controller below to illustrate how it now gets its dependencies:
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
namespace IntegrationReceiver.WebApi
{
public class HealthCheckController : ApiController
{
private readonly ServiceBusRunner serviceBusRunner;
public HealthCheckController(ServiceBusRunner serviceBusRunner)
{
this.serviceBusRunner = serviceBusRunner;
}
[HttpGet]
public async Task<HttpResponseMessage> Get()
{
var response = new
{
serviceBusRunner.RunningTasks,
serviceBusRunner.MaxRunningTasks
};
return await Json(response)
.ExecuteAsync(System.Threading.CancellationToken.None);
}
}
}
This is a pretty dumb-down implementation but works for me until I can upgrade this code to net5.
I hope it helps you too!
I'm using MySQL with EF Core. I am currently using Pomelo Provider for MySQL. I need to implement Unit Of Work Pattern for transactions. I have a Service which calls two methods in repository. I am not able to implement nested transactions. This is how my method in service looks now:
public void methodA(param)
{
using (TransactionScope tx = new
TransactionScope(TransactionScopeOption.Required))
{
repo1.save(data1);
repo2.save(data2);
tx.complete();
}
}
This is how save method in repo1 is implemented
private readonly UserDbContext appDbContext;
public repo1(UserDbContext _appDbContext)
{
appDbContext = _appDbContext;
}
public void save(User entity)
{
var dbset = appDbContext.Set<User>().Add(entity);
appDbContext.SaveChanges();
}
This is how save method in repo2 is implemented
private readonly UserDbContext appDbContext;
public repo2(UserDbContext _appDbContext)
{
appDbContext = _appDbContext;
}
public void save(UserRole entity)
{
var dbset = appDbContext.Set<UserRole>().Add(entity);
appDbContext.SaveChanges();
}
I am getting the following error while running method in service:
Error generated for warning 'Microsoft.EntityFrameworkCore.Database.Transaction.AmbientTransactionWarning: An ambient transaction has been detected. The current provider does not support ambient transactions. See http://go.microsoft.com/fwlink/?LinkId=800142'. This exception can be suppressed or logged by passing event ID 'RelationalEventId.AmbientTransactionWarning' to the 'ConfigureWarnings' method in 'DbContext.OnConfiguring' or 'AddDbContext'.
This is how I registered UserDbContext in Startup.cs
services.AddDbContext<UserDbContext>(options => options.UseLazyLoadingProxies().UseMySql("Server = xxxx; Database = xxx; Uid = xx;ConnectionReset=True;", b => b.MigrationsAssembly("AssemblyName")));
I even tried adding a middleware which starts transaction at the begining of request and commits/rollbacks during the response . But still I am not able to manage nested transactions.
This is how my middleware looks:
public class TransactionPerRequestMiddleware
{
private readonly RequestDelegate next_;
public TransactionPerRequestMiddleware(RequestDelegate next)
{
next_ = next;
}
public async Task Invoke(HttpContext context, UserDbContext
userDbContext)
{
var transaction = userDbContext.Database.BeginTransaction(
System.Data.IsolationLevel.ReadCommitted);
await next_.Invoke(context);
int statusCode = context.Response.StatusCode;
if (statusCode == 200 || statusCode==302)
{
transaction.Commit();
}
else
{
transaction.Rollback();
}
}
}
Can anyone help me please?
I am trying to execute a package programmatically. The SSIS packages were deployed using the Project deployment model. I used the following as the example:
http://microsoft-ssis.blogspot.com/2013/01/call-ssis-2012-package-within-net.html
// Connection to the database server where the packages are located
SqlConnection ssisConnection = new SqlConnection
(#"Data Source=SSIS_SERVER;Initial Catalog=master;
Integrated Security=SSPI;");
// SSIS server object with connection
IntegrationServices ssisServer = new IntegrationServices(ssisConnection);
// The reference to the package which you want to execute
// (Note: formatted for ease of reading)
PackageInfo ssisPackage = ssisServer
.Catalogs["SSISDB"]
.Folders["DEV_FOLDER"]
.Projects["TestParentChildDeployment"]
.Packages["Child.dtsx"];
// Add execution parameter to override the default asynchronized execution.
//If you leave this out the package is executed asynchronized
//Collection<PackageInfo.ExecutionValueParameterSet> executionParameter
// = new Collection<PackageInfo.ExecutionValueParameterSet>();
var executionParameter = new Collection<PackageInfo
.ExecutionValueParameterSet>();
executionParameter.Add
(new PackageInfo.ExecutionValueParameterSet
{
ObjectType = 50
, ParameterName = "SYNCHRONIZED"
, ParameterValue = 1
}
);
// Get the identifier of the execution to get the log
long executionIdentifier = ssisPackage.Execute (false, null, executionParameter); // Times out here <<<<
Here is the error: Message=Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
It runs successfully once in a while, but more often than not, it fails. Any ideas?
Here is my solution. Instead of calling the package synchronously, call is asynchronously and use a ManualResetEvent in the calling code to block the main thread until the package completes.
namespace Anthony.Staging.Integration.Tests
{
using System;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Microsoft.SqlServer.Management.Common;
using Microsoft.VisualStudio.TestTools.UnitTesting;
//Add references via %WINDIR%\assembly\GAC_MSIL\:
/* Microsoft.SqlServer.ConnectionInfo
* Microsoft.SqlServer.Management.InterationServices
* Microsoft.SqlServer.Management.Sdk.Sfc
* Microsoft.SqlServer.Smo
*/
using Microsoft.SqlServer.Management.IntegrationServices;
[TestClass]
public class ConnectionTests
{
private const string connectionString = #"Data Source=Anthony\MSSQL11;Initial Catalog=SSISDB;Integrated Security=SSPI;";
private static SqlConnection connection;
private static ServerConnection conn;
private static IntegrationServices ssis;
private static string catalog = "SSISDB";
private static string folder = "Anthony.Integration";
[TestInitialize]
public void MyTestInitialize()
{
connection = new SqlConnection(connectionString);
ssis = new IntegrationServices(connection);
}
[TestMethod]
public void CanConnect()
{
Assert.IsNotNull(connection);
Assert.IsTrue(connection.State == ConnectionState.Open);
}
[TestMethod]
public void CanGetKnownPackage()
{
try
{
var package = this.GetPackage(catalog, folder, "Anthony.Staging", "_Extract_Full.dtsx");
Assert.IsNotNull(package);
}
catch (Exception ex)
{
Assert.Fail(ex.Message);
}
}
[TestMethod]
public void CanExecuteKnownPackage()
{
const int MAX_RETRIES = 20;
const int RETRY_INTERVAL_SECONDS = 10;
const int OPERATION_TIMEOUT_MINUTES = 10;
// get the package from the SSISCatalog and start it asynchronously
// because starting it synchronously will time out after 30 seconds.
var package = this.GetPackage(catalog, folder, "Anthony.Staging", "_Extract_Full.dtsx");
var executionIdentifier = package.Execute(false, null);
// block the main thread and kick off a timer immediately which checks execution status for an ssis execution identifier.
var mre = new ManualResetEvent(false);
var statusChecker = new StatusChecker(executionIdentifier, MAX_RETRIES);
var timer = new Timer(statusChecker.CheckStatus, new StatusCheckerState(mre), new TimeSpan(0, 0, 0), new TimeSpan(0, 0, RETRY_INTERVAL_SECONDS));
WaitHandle.WaitAny(new WaitHandle[] { mre }, (int)new TimeSpan(0, OPERATION_TIMEOUT_MINUTES, 0).TotalMilliseconds, false);
mre.Dispose();
timer.Dispose();
// get the results
var execution = ssis.Catalogs.Single(x => x.Name.Equals(catalog)).Executions.Single(x => x.Id.Equals(executionIdentifier));
var errors = execution.Messages.Where(m => m.MessageType == 120).Select(m => m.Message);
var warnings = execution.Messages.Where(m => m.MessageType == 110).Select(m => m.Message);
Assert.AreEqual(0, errors.Count());
Assert.AreEqual(Operation.ServerOperationStatus.Success, execution.Status);
}
class StatusCheckerState
{
public StatusCheckerState(ManualResetEvent waitHandle)
{
this.WaitHandle = waitHandle;
}
public ManualResetEvent WaitHandle { get; private set; }
}
class StatusChecker
{
private readonly long executionIdentifier;
private int invokeCount;
private ManualResetEvent waitHandle;
private readonly int maximumCount;
public StatusChecker(long executionIdentifier, int maxCount)
{
this.executionIdentifier = executionIdentifier;
invokeCount = 0;
maximumCount = maxCount;
}
// This method is called by the timer delegate.
public void CheckStatus(object state)
{
var localState = ((StatusCheckerState)state);
this.waitHandle = localState.WaitHandle;
if (invokeCount > 0)
{
Debug.WriteLine("Retry attempt: {0}", invokeCount);
}
invokeCount++;
if (invokeCount == maximumCount)
{
// Reset the counter and signal Main.
invokeCount = 0;
waitHandle.Set();
}
var execution = new IntegrationServices(connection).Catalogs.Single(x => x.Name.Equals(catalog)).Executions.Single(x => x.Id.Equals(executionIdentifier));
Debug.WriteLine("Status of execution " + executionIdentifier + " is " + execution.Status);
if (execution.Status == Operation.ServerOperationStatus.Success)
{
// Reset the counter and signal Main.
invokeCount = 0;
waitHandle.Set();
}
}
}
[TestCleanup]
public void MyTestCleanup()
{
if(connection.State == ConnectionState.Open)
connection.Close();
ssis = null;
}
private PackageInfo GetPackage(string catalog, string folder, string project, string package)
{
if (ssis.Catalogs.Contains(catalog))
{
var cat = ssis.Catalogs[catalog];
if (cat.Folders.Contains(folder))
{
var fold = cat.Folders[folder];
if (fold.Projects.Contains(project))
{
var proj = fold.Projects[project];
if (proj.Packages.Contains(package))
{
var pkg = proj.Packages[package];
return pkg;
}
}
}
}
throw new Exception("Cannot find package!");
}
}
}
Here is some code to solve the timeout... it's a bit dirty, but works great:
// Get the identifier of the execution to get the log
long executionIdentifier = ssisPackage.Execute(false, null, executionParameter);
/****
* This is a shameful workaround to not having a timeout override
* for PackageInfo.Execute.
****/
ExecutionOperation executionOperation = ssisServer.Catalogs["SSISDB"].Executions[executionIdentifier];
while (!(executionOperation.Completed))
{
executionOperation.Refresh();
System.Threading.Thread.Sleep(5000);
}
Source:
https://social.msdn.microsoft.com/Forums/sqlserver/en-US/7f0967af-fdeb-4040-9c57-2fe14f2291b5/timeout-after-30-seconds-when-executing-package-via-net?forum=sqlintegrationservices
I have this first version of a class
public class GenerateAuthorisationWorkflows : IGenerateAuthorisationWorkflows
{
public IList<Guid> FromDtaObjects(IList<DtaObject> dtaObjects, Employee requestingEmployee)
{
foreach (var dtaObject in dtaObjects) { }
return new List<Guid>();
}
public IList<Guid> FromDtaObjects()
{
return new List<Guid>();
}
}
And the MSpec tests for it
public abstract class specification_for_generate_workflows : Specification<GenerateAuthorisationWorkflows>
{
protected static IWorkflowService workflowService;
Establish context = () => { workflowService = DependencyOf<IWorkflowService>(); };
}
[Subject(typeof(GenerateAuthorisationWorkflows))]
public class when_generate_workflows_is_called_with_a_dta_object_list_and_an_employee : specification_for_generate_workflows
{
static IList<Guid> result;
static IList<DtaObject> dtaObjects;
static Employee requestingEmployee;
Establish context = () =>
{
var mocks = new MockRepository();
var stubDtaObject1 = mocks.Stub<DtaObject>();
var stubDtaObject2 = mocks.Stub<DtaObject>();
var dtaObjectEnum = new List<DtaObject>{stubDtaObject1,stubDtaObject2}.GetEnumerator();
dtaObjects = mocks.Stub<IList<DtaObject>>();
dtaObjects.Stub(x => x.GetEnumerator()).Return(dtaObjectEnum).WhenCalled(x => x.ReturnValue = dtaObjectEnum);
requestingEmployee = mocks.Stub<Employee>();
mocks.ReplayAll();
};
Because of = () => result = subject.FromDtaObjects(dtaObjects, requestingEmployee);
It should_enumerate_the_dta_objects = () => dtaObjects.received(x=> x.GetEnumerator());
It should_call_workflow_host_helper = () => workflowService.AssertWasCalled(x => x.StartWorkflow());
}
With this configuration, my first test passes and my second test fails, as expected. I added a constructor to the class to inject the IWorkflowService.
public class GenerateAuthorisationWorkflows : IGenerateAuthorisationWorkflows
{
IWorkflowService _workflowService;
GenerateAuthorisationWorkflows(IWorkflowService workflowService)
{
_workflowService = workflowService;
}
public IList<Guid> FromDtaObjects(IList<DtaObject> dtaObjects, Employee requestingEmployee)
{
foreach (var dtaObject in dtaObjects)
{
Guid workflowKey = _workflowService.StartWorkflow();
}
return new List<Guid>();
}
public IList<Guid> FromDtaObjects()
{
return new List<Guid>();
}
}
Now, when I run the tests, they fail at the Because:
System.InvalidOperationException: Sequence contains no elements
at System.Linq.Enumerable.First(IEnumerable`1 source)
at MSpecTests.EmployeeRequestSystem.Tasks.Workflows.when_generate_workflows_is_called_with_a_dta_object_list_and_an_employee.<.ctor>b__4() in GenerateAuthorisationWorkflowsSpecs.cs: line 76
For clarity, line 76 above is:
Because of = () => result = subject.FromDtaObjects(dtaObjects, requestingEmployee);
I've tried tracing the problem but am having no luck. I have tried setting up a constructor that takes no arguments but it raises the same error. I have similar classes with IoC dependencies that work fine using MSpec/Rhino Mocks, where am I going wrong?
Castle Windsor requires a public constructor to instantiate a class. Adding public to the constructor allows correct operation.
public class GenerateAuthorisationWorkflows : IGenerateAuthorisationWorkflows
{
IWorkflowService _workflowService;
public GenerateAuthorisationWorkflows(IWorkflowService workflowService)
{
_workflowService = workflowService;
}
public IList<Guid> FromDtaObjects(IList<DtaObject> dtaObjects, Employee requestingEmployee)
{
foreach (var dtaObject in dtaObjects)
{
Guid workflowKey = _workflowService.StartWorkflow();
}
return new List<Guid>();
}
public IList<Guid> FromDtaObjects()
{
return new List<Guid>();
}
}
Rowan, looks like you answered your own question. It's good practice to explicitly state the access modifiers! By default, C# chooses private. These kinds of errors are easy to miss!
I can also see that your Establish block is too complicated. You're testing the implementation details and not the behavior. For example, you are
stubbing the GetEnumerator call that's implicitly made inside the foreach loop.
asserting that the workflow service was called only once
mixing MSpec automocking and your own local mocks
You're not actually testing that you got a GUID for every object in the input list. If I were you, I'd test the behavior like this...
public class GenerateAuthorisationWorkflows : IGenerateAuthorisationWorkflows
{
private readonly IWorkflowService _service;
public GenerateAuthorisationWorkflows(IWorkflowService service)
{
_service = service;
}
public List<Guid> FromDtaObjects(List<DtaObject> input, Employee requestor)
{
// I assume that the workflow service generates a new key
// per input object. So, let's pretend the call looks like
// this. Also using some LINQ to avoid the foreach or
// building up a local list.
input.Select(x => _service.StartWorkflow(requestor, x)).ToList();
}
}
[Subject(typeof(GenerateAuthorisationWorkflows))]
public class When_generating_authorisation_keys_for_this_input
: Specification<GenerateAuthorisationWorkflows>
{
private static IWorkflowService _service;
private static Employee _requestor = new Employee();
private static List<DtaObject> _input = new List<DtaObject>()
{
new DtaObject(),
new DtaObject(),
};
private static List<Guid> _expected = new List<Guid>()
{
Guid.NewGuid(),
Guid.NewGuid(),
};
private static List<Guid> _actual = new List<Guid>();
Establish context = () =>
{
// LINQ that takes each item from each list in a pair. So
// the service is stubbed to return a specific GUID per
// input DtaObject.
_input.Zip(_expected, (input, output) =>
{
DependencyOf<IWorkflowService>().Stub(x => x.StartWorkflow(_requestor, input)).Return(output);
});
};
Because of = () => _actual = Subject.FromDtaObjects(_input, _requestor);
// This should be an MSpec collection assertion that
// ensures that the contents of the collections are
// equivalent
It should_get_a_unique_key_per_input = _actual.ShouldEqual(_expected);
}
I'm using Windsor to manage IoC for my controllers in a WebAPI project. I've got a DependencyResolver working nicely to resolve controller dependencies, but now I'm looking to inject dependencies into a custom action filter I'm using to manage authentication.
I've looked into using a custom ActionInvoker but it's not clear from the interface that WebAPI is using how I would go about resolving property dependencies on the custom action filter attribute before it executes. Anyone have a good example of how to do this in the MVC 4 RC?
EDIT: I'm aware you can't do constructor injection on filters, because they're attributes and therefore instantiated by the .NET framework - but I'm hoping there's some point in the execution lifecycle that happens AFTER the filter is instantiated but BEFORE it gets executed, where I could run some custom code to enumerate across the filters' public properties and inject the necessary services.
Action filters are attributes. In .NET attribute the instantiation process is managed by the .NET runtime and you don't have control over it. So one possibility is to use Poor Man's Dependency Injection which I would personally advice you against.
Another possibility is to use a marker attribute:
public class MyActionFilterAttribute : Attribute
{
}
and then have the action filter using constructor injection:
public class MyActionFilter : ActionFilterAttribute
{
private readonly IFoo _foo;
public MyActionFilter(IFoo foo)
{
_foo = foo;
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.ActionDescriptor.GetCustomAttributes<MyActionFilterAttribute>().Any())
{
// The action is decorated with the marker attribute =>
// do something with _foo
}
}
}
and then register it as a global action filter in Application_Start:
IFoo foo = ....
GlobalConfiguration.Configuration.Filters.Add(new MyActionFilter(foo));
I had the same problem, but decided to go for the ServiceLocator (DependencyResolver.GetService) for this, as its in the framework it seems to me to be a valid approach
public class RequiresSessionAttribute :
ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var sessionService =
(ISessionService) actionContext
.ControllerContext.Configuration.DependencyResolver
.GetService(typeof (ISessionService));
var sessionId = HttpUtility
.ParseQueryString(actionContext.Request.RequestUri.Query)
.Get("sessionId");
if (sessionId == null
|| !sessionService.IsValid(sessionId))
throw new SessionException();
base.OnActionExecuting(actionContext);
}
}
and here is a test for this attribute, bit of a pain but possible
public class requires_sessionId
{
[Fact]
void can_call_action_with_session_id()
{
var context = GetContext("http://example.com/?sessionId=blaa");
var sut = new RequiresSessionAttribute();
Assert.DoesNotThrow(
() => sut.OnActionExecuting(context));
}
[Fact]
void can_not_call_action_without_session_id()
{
var context = GetContext("http://example.com/");
var sut = new RequiresSessionAttribute();
Assert.Throws<SessionException>(
() => sut.OnActionExecuting(context));
}
HttpActionContext GetContext(string url)
{
var sessionServiceMock = new Mock<ISessionService>();
sessionServiceMock
.Setup(x => x.IsValid(It.IsAny<string>()))
.Returns(true);
var dependancyResolverMock = new Mock<IDependencyResolver>();
dependancyResolverMock
.Setup(x => x.GetService(It.IsAny<Type>()))
.Returns(sessionServiceMock.Object);
var config = new HttpConfiguration
{
DependencyResolver = dependancyResolverMock.Object
};
var controllerContext = new HttpControllerContext
{
Configuration = config,
Request = new HttpRequestMessage(
HttpMethod.Get,
url)
};
return
new HttpActionContext
{
ControllerContext = controllerContext,
};
}
}