object reference not set to instance of an object issues in unit testing of asp.net mvc - asp.net

I am the beginner of writing unit tests for asp.net. I created a simple project and try to start my testing journey. However, I met two errors with the same issue:"object reference not set to instance of an object" The first place is in the home controller as below:
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
Here is my test method:
public class HomeControllerUnitTests
{
ILogger<HomeController> _logger;
[Fact]
public void Error_ActionExecutes_ReturnsAViewResult()
{
// Arrange
var homeController = new HomeController(_logger);
// Act
var result = homeController.Error() as ViewResult;
// Assert
Assert.Null(result.ViewData.Model);
}
}
The second place is in the Movie Controller:
public class MoviesController : Controller
{
private readonly MvcMovieContext _context;
public MoviesController(MvcMovieContext context)
{
_context = context;
}
// GET: Movies
public async Task<IActionResult> Index()
{
return View(await _context.Movie.ToListAsync());
}
}
My test method is as below:
public class MoviesControllerUnitTests
{
private Mock<MvcMovieContext> _mock;
[Fact]
public async Task Index_ActionExecutes_ReturnsAViewResult()
{
// Arrange
MoviesController controller = new MoviesController(_mock.Object);
// Act
var result = await controller.Index() as Task<ViewResult>;
// Assert
Assert.IsType<ViewResult>(result);
}
}
Please help me and thanks in advance.

Below the Object reference not set to an instance of an object line there should be an indication about which file and line the error occurred, which helps you to determine which variables are null (but you could also use the debugger).
For the MoviesControllerUnitTests this probably is the _mock variable, so be sure to initialize it as shown in the docs, e.g.:
private Mock<MvcMovieContext> _mock = new Mock<MvcMovieContext>();
For the HomeControllerUnitTests you might need to mock the Activity or set a HttpContext (see e.g. this question).

Related

how moq one of the interfaces in controller test

I have a controller class with 2 service interfaces: one is a post method of external URL and the second is a local repository. In the controller test class, I just want to moq the interface1, not the second. How can I do this? Or what is the best way to test this controller?
[Route("api/MyAPI")]
[ApiController]
public class MyAPIController : Controller
{
private readonly Interface1 _interface1;
private readonly Interface2 _interface2;
public ProfitLossGrowthRateController(Interface1 interface1,
Interface2 interface2)
{
_interface1= interface1;
_interface2 = interface2;
}
[HttpPost("CodeAPI")]
[Produces(MediaTypeNames.Application.Json)]
[ProducesResponseType(typeof(List<Response>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(Error), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(Error), StatusCodes.Status500InternalServerError)]
public async Task<List<Response>> GetCodeAPIController
(Request request)
{
var response1 = await _interface1.GetCodesByFilter(request);
return await _interface2.GetGrowthRate(response1.Codes);
}
}
, meanwhile, in the first version of this controller when I don't have the first interface, I write my controller test like this and it works correctly:
public class MyAPIControllerTest : IntegrationBaseTest
{
public MyAPIControllerTest ()
: base(nameof(Repository))
{
DataProvider.InsertData<Data1>
(Context, nameof(Data1));
}
[Theory]
[InlineData("/api/MyAPI/CodeAPI")]
public async Task GetGrowthRate(string url)
{
var request = new Request()
{
Filter = new List<string>() { "111" }
};
var content = await HttpHandler.PostURI<Request>(url, request, Factory);
List<Response> response = JsonConvert.DeserializeObject<List<Response>>(content);
// Assert
Assert.NotNull(response);
Assert.Single(response);
Assert.Equal("111", response[0].CompanyNationalCode);
}
}

How to do UnitOfWork + Repository patterns with entity framework core and unit testing

I'm running into an issue while unit testing where if I run multiple tests at once, the DbContext will lose track of records I've added during unit tests and I think this may have to do with how services are registered in my ServiceCollection.
I have the following setup:
IUnitOfWork:
public interface IUnitOfWork : IDisposable
{
IUserRepository Users { get; }
int Complete();
}
UnitOfWork
public class UnitOfWork : IUnitOfWork
{
private readonly MyDbContext _context;
public IUserRepository Users { get; }
public UnitOfWork(MyDbContext context,
IUserRepository userRepository)
{
_context = context;
Users = userRepository;
}
public void Dispose() => _context.Dispose();
public int Complete() => _context.SaveChanges();
}
UserRepository
public class UserRepository : Repository<User>, IUserRepository
{
public UserRepository(MyDbContext context) : base(context) { }
public MyDbContext MyDbContext => Context as MyDbContext;
public Task<User?> GetUserDetailsAsync(int userID)
{
var user = MyDbContext.Users.Where(user => user.Id == userID)
.Include(user => user.Emails)
.Include(user => user.PhoneNumbers).FirstOrDefault();
return Task.FromResult(user);
}
}
Here is my base test:
public abstract class BaseTest : IDisposable
{
protected ServiceProvider ServiceProvider { get; }
private MyDbContext MyDbContext { get; }
protected IUnitOfWork UnitOfWork { get; }
public BaseTest()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddScoped<IUserService, UserService>()
.AddScoped<IUnitOfWork, UnitOfWork>()
.AddScoped(typeof(IRepository<>), typeof(Repository<>))
.AddScoped<IOrganizationRepository, OrganizationRepository>()
.AddScoped<IExercisePostRepository, ExercisePostRepository>()
.AddScoped<IUserRepository, UserRepository>()
.AddTransient<IRestClient, RestClient>()
.AddAutoMapper(typeof(Startup).Assembly)
.AddDbContext<MyDbContext>(options =>
options.UseInMemoryDatabase("Core")
.EnableSensitiveDataLogging());
ServiceProvider = serviceCollection.BuildServiceProvider();
SpotcheckrCoreContext = ServiceProvider.GetRequiredService<MyDbContext>();
MyDbContext.Database.EnsureCreated();
UnitOfWork = ServiceProvider.GetRequiredService<IUnitOfWork>();
}
public void Dispose()
{
MyDbContext.Database.EnsureDeleted();
UnitOfWork.Dispose();
}
}
Sample test:
public class UserServiceTests : BaseTest
{
private readonly IUnitOfWork UnitOfWork;
private readonly IUserService Service;
public UserServiceTests()
{
UnitOfWork = ServiceProvider.GetRequiredService<IUnitOfWork>();
Service = ServiceProvider.GetRequiredService<IUserService>();
}
[Fact]
public async void GetUserAsync_WithValidUser_ReturnsUser()
{
var user = new User
{
FirstName = "John",
LastName = "Doe"
};
UnitOfWork.Users.Add(user);
UnitOfWork.Complete();
var result = await Service.GetUserAsync(user.Id);
Assert.Equal(user.Id, result.Id);
}
}
If I run this test by itself, then it will correctly pass and I can see the user in the repository. However if I run it with other tests and debug, then that user is lost once I inspect UnitOfWork.Users in the repository but I do see it in the UnitOfWork.Users in the test.
What is the correct approach here?
Edit 1:
Tried some other changes but no luck yet. Adjusted UnitOfWork to take in the interfaces of each repository and registering them in BaseTest as scoped services. Also tried marking BaseTest as implementing IDisposable and then executing:
public void Dispose()
{
MyDbContext.Database.EnsureDeleted();
UnitOfWork.Dispose();
}
In the service layer I'll see the Users just fine but as soon as I step into the repository layer I'll lose the Users :/ I have a suspicion it is related to dependency injection AddScoped vs AddTransient and how all of that works with running multiple unit tests.
Edit 2:
Tried some more things...Used IClassFixture<BaseTest> on each test class and then ensured that each test class implemented IDisposable and in there I would ensure the Context database was deleted; also ensured in the test class constructor that it was created. With this I ended up with the following error:
The instance of entity type cannot be tracked because another instance with the same key value for {'Id'} is already being tracked
And so I added .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking) but the problem still persisted.
This is very annoying to setup.
This is what has resolved it for me for now.
Summary: Created a new ServiceFixture. This ServiceFixture is applied to a BaseTest class as IClassFixture<ServiceFixture>. The ServiceFixture is responsible for initializing the service collection and allowing for it to be reused across different test classes. The purpose of the BaseTest is to allow for disposal of the database and other clean up that is necessary after each test. The Dispose method of this class will detach entity state and also delete the database.
ServiceFixture.cs
public class ServiceFixture
{
public ServiceProvider ServiceProvider { get; }
public ServiceFixture()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddScoped<IUserService, UserService>()
.AddScoped<ICertificationService, CertificationService>()
.AddScoped<IOrganizationService, OrganizationService>()
.AddScoped<ICertificateService, CertificateService>()
.AddScoped<IUnitOfWork, UnitOfWork>()
.AddScoped<IUserRepository, UserRepository>()
.AddScoped<IExercisePostRepository, ExercisePostRepository>()
.AddScoped<IEmailRepository, EmailRepository>()
.AddScoped<IPhoneNumberRepository, PhoneNumberRepository>()
.AddScoped<ICertificationRepository, CertificationRepository>()
.AddScoped<ICertificateRepository, CertificateRepository>()
.AddScoped<IOrganizationRepository, OrganizationRepository>()
.AddTransient<IRestClient, RestClient>()
.AddSingleton<NASMCertificationValidator>()
.AddAutoMapper(typeof(Startup).Assembly)
.AddDbContext<SpotcheckrCoreContext>(options =>
options.UseInMemoryDatabase("Spotcheckr-Core")
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)
.EnableSensitiveDataLogging());
ServiceProvider = serviceCollection.BuildServiceProvider();
}
}
BaseTest.cs
public abstract class BaseTest : IClassFixture<ServiceFixture>, IDisposable
{
protected readonly ServiceProvider ServiceProvider;
protected readonly IUnitOfWork UnitOfWork;
private readonly SpotcheckrCoreContext Context;
public BaseTest(ServiceFixture serviceFixture)
{
ServiceProvider = serviceFixture.ServiceProvider;
Context = serviceFixture.ServiceProvider.GetRequiredService<SpotcheckrCoreContext>();
UnitOfWork = serviceFixture.ServiceProvider.GetRequiredService<IUnitOfWork>();
Context.Database.EnsureCreated();
}
public void Dispose()
{
Context.ChangeTracker.Entries().ToList().ForEach(entry => entry.State = EntityState.Detached);
Context.Database.EnsureDeleted();
}
}
UserServiceTests.cs
public class UserServiceTests : BaseTest
{
private readonly IUserService Service;
public UserServiceTests(ServiceFixture serviceFixture) : base(serviceFixture)
{
Service = serviceFixture.ServiceProvider.GetRequiredService<IUserService>();
}
[Fact]
public async void GetUserAsync_WithInvalidUser_ThrowsException()
{
Assert.ThrowsAsync<InvalidOperationException>(() => Service.GetUserAsync(-1));
}
[Fact]
public void CreateUser_UserTypeAthlete_CreatesAthleteUser()
{
var result = Service.CreateUser(Models.UserType.Athlete);
Assert.IsType<Athlete>(result);
}
[Fact]
public void CreateUser_UserTypePersonalTrainer_CreatesPersonalTrainerUser()
{
var result = Service.CreateUser(Models.UserType.PersonalTrainer);
Assert.IsType<PersonalTrainer>(result);
}
}

asp.net api error - return ambiguousMatchException or page not found

i have an problem with call to api, i get ambiguousMatchException: The request matched multiple endpoints
or page not found.
this happen after i add testApi to my controller, before all works good.
why it's happen and how to fix it? i want to add more function to this controller.
thank's!!!!!!
my code:
namespace AutomationTool.Api
{
[Route("api/[controller]")]
[ApiController]
public class TestCasesController : ControllerBase
{
private readonly ApplicationDbContext _context;
public TestCasesController(ApplicationDbContext context)
{
_context = context;
}
[HttpGet("{id:int}")] -- > here the problem
public int testApi(int id)
{
return 1;
}
// GET: api/TestCases
[HttpGet]
public async Task<ActionResult<IEnumerable<TestCase>>> GetTestCases()
{
return await _context.TestCases.ToListAsync();
}
// GET: api/TestCases/5
[HttpGet("{id}")]
public async Task<ActionResult<TestCase>> GetTestCase(int id)
{
var testCase = await _context.TestCases.FindAsync(id);
if (testCase == null)
{
return NotFound();
}
return testCase;
}
}
}

HttpContext is NULL after using DependencyResolver with Ninject

I implemented custom IIdentityMessageService class. My implementation simply put messages into database. I use Dependency resolver to create instance of repository class.
public class QueueSmsService : IIdentityMessageService
{
public Task SendAsync(IdentityMessage message)
{
var smsRepository = DependencyResolver.Current.GetService<ISmsRepository>();
Sms smsMessage = new Sms()
{
Priority = (int)MessagePriority.High,
NumberTo = message.Destination,
Body = message.Body
};
return smsRepository.InsertAndSubmitAsync(smsMessage);
}
}
Unfortunately there is a problem with HttpContext being null. Maybe if I inject repository in contructor would solve the problem? Can I somehow inject repository in contructor? Maybe there is another solution to eliminate the HttpContect == null problem? Right now QueueSmsService is created like below in:
var manager = new AppUserManager(new AppUserStore(context.Get<DataContext>()));
manager.RegisterTwoFactorProvider("SMS", new PhoneNumberTokenProvider<User, int>
{
MessageFormat = "Kod autentykujÄ…cy: {0}"
});
manager.EmailService = new QueueEmailService();
manager.SmsService = new QueueSmsService();
HttpContext is used in repository class
public abstract class RepositoryBase<T> : IRepositoryBase<T> where T : class
{
private IDataContext dataContext;
private readonly IHttpContextFactory httpContextFactory;
protected static Logger logger = LogManager.GetCurrentClassLogger();
public RepositoryBase(IDataContext dataContext, IHttpContextFactory httpContext)
{
if (httpContext == null) throw new ArgumentNullException("httpContextFactory");
this.httpContextFactory = httpContext;
this.dataContext = dataContext;
}
(...)
Where the DataContxtFactory is simply
public class HttpContextFactory : IHttpContextFactory
{
public HttpContextBase Create()
{
return new HttpContextWrapper(HttpContext.Current);
}
}
And the error is reported exactly in the code above.

NHibernate in Web API ASP.NET: No session bound to the current context

I'm new to NHibernate and trying to use it in ASP.NET WEB API. Firstly I used it successfully with one table named "Category" which the controller class is as follow:
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using TestMVCProject.Web.Api.HttpFetchers;
using TestMVCProject.Web.Api.Models;
using TestMVCProject.Web.Api.TypeMappers;
using TestMVCProject.Web.Common;
//using TestMVCProject.Web.Common.Security;
using NHibernate;
namespace TestMVCProject.Web.Api.Controllers
{
[LoggingNHibernateSession]
public class CategoryController : ApiController
{
private readonly ISession _session;
private readonly ICategoryMapper _categoryMapper;
private readonly IHttpCategoryFetcher _categoryFetcher;
public CategoryController(
ISession session,
ICategoryMapper categoryMapper,
IHttpCategoryFetcher categoryFetcher)
{
_session = session;
_categoryMapper = categoryMapper;
_categoryFetcher = categoryFetcher;
}
public IEnumerable<Category> Get()
{
return _session
.QueryOver<Data.Model.Category>()
.List()
.Select(_categoryMapper.CreateCategory)
.ToList();
}
public Category Get(long id)
{
var category = _categoryFetcher.GetCategory(id);
return _categoryMapper.CreateCategory(category);
}
public HttpResponseMessage Post(HttpRequestMessage request, Category category)
{
var modelCategory = new Data.Model.Category
{
Description = category.Description,
CategoryName = category.CategoryName
};
_session.Save(modelCategory);
var newCategory = _categoryMapper.CreateCategory(modelCategory);
//var href = newCategory.Links.First(x => x.Rel == "self").Href;
var response = request.CreateResponse(HttpStatusCode.Created, newCategory);
//response.Headers.Add("Location", href);
return response;
}
public HttpResponseMessage Delete()
{
var categories = _session.QueryOver<Data.Model.Category>().List();
foreach (var category in categories)
{
_session.Delete(category);
}
return new HttpResponseMessage(HttpStatusCode.OK);
}
public HttpResponseMessage Delete(long id)
{
var category = _session.Get<Data.Model.Category>(id);
if (category != null)
{
_session.Delete(category);
}
return new HttpResponseMessage(HttpStatusCode.OK);
}
public Category Put(long id, Category category)
{
var modelCateogry = _categoryFetcher.GetCategory(id);
modelCateogry.CategoryName = category.CategoryName;
modelCateogry.Description = category.Description;
_session.SaveOrUpdate(modelCateogry);
return _categoryMapper.CreateCategory(modelCateogry);
}
}
}
But when I add The "Product" table which has a foreign key of the Category table, the product controller doesn't work and throws below exception:
No session bound to the current context
ProductController class is as follow:
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using TestMVCProject.Web.Api.HttpFetchers;
using TestMVCProject.Web.Api.Models;
using TestMVCProject.Web.Api.TypeMappers;
using TestMVCProject.Web.Common;
//using TestMVCProject.Web.Common.Security;
using NHibernate;
namespace TestMVCProject.Web.Api.Controllers
{
[LoggingNHibernateSession]
public class ProductController : ApiController
{
private readonly ISession _session;
private readonly IProductMapper _productMapper;
private readonly IHttpProductFetcher _productFetcher;
public ProductController(
ISession session,
IProductMapper productMapper,
IHttpProductFetcher productFetcher)
{
_session = session;
_productMapper = productMapper;
_productFetcher = productFetcher;
}
public IEnumerable<Product> Get()
{
return _session
.QueryOver<Data.Model.Product>()
.List()
.Select(_productMapper.CreateProduct)
.ToList();
}
public Product Get(long id)
{
var product = _productFetcher.GetProduct(id);
return _productMapper.CreateProduct(product);
}
public HttpResponseMessage Post(HttpRequestMessage request, Product product)
{
var modelProduct = new Data.Model.Product
{
Description = product.Description,
ProductName = product.ProductName
};
_session.Save(modelProduct);
var newProduct = _productMapper.CreateProduct(modelProduct);
//var href = newproduct.Links.First(x => x.Rel == "self").Href;
var response = request.CreateResponse(HttpStatusCode.Created, newProduct);
//response.Headers.Add("Location", href);
return response;
}
public HttpResponseMessage Delete()
{
var categories = _session.QueryOver<Data.Model.Product>().List();
foreach (var product in categories)
{
_session.Delete(product);
}
return new HttpResponseMessage(HttpStatusCode.OK);
}
public HttpResponseMessage Delete(long id)
{
var product = _session.Get<Data.Model.Product>(id);
if (product != null)
{
_session.Delete(product);
}
return new HttpResponseMessage(HttpStatusCode.OK);
}
public Product Put(long id, Product product)
{
var modelProduct = _productFetcher.GetProduct(id);
modelProduct.ProductName = product.ProductName;
modelProduct.Description = product.Description;
_session.SaveOrUpdate(modelProduct);
return _productMapper.CreateProduct(modelProduct);
}
}
}
and the mapping class for Product table:
using TestMVCProject.Data.Model;
using FluentNHibernate.Mapping;
namespace TestMVCProject.Data.SqlServer.Mapping
{
public class ProductMap : ClassMap<Product>
{
public ProductMap()
{
Id(x => x.ProductId);
Map(x => x.ProductName).Not.Nullable();
Map(x => x.Description).Nullable();
Map(x => x.CreateDate).Not.Nullable();
Map(x => x.Price).Not.Nullable();
References<Category>(x => x.CategoryId).Not.Nullable();
}
}
}
What is wrong?
Your snippets are missing the way, how the ISessionFactory is created and how ISession is passed into your controllers... You should follow this really comprehensive story (by Piotr Walat):
NHibernate session management in ASP.NET Web API
Where you can see that we, can use 2.3. Contextual Sessions:
NHibernate.Context.WebSessionContext - stores the current session in HttpContext. You are responsible to bind and unbind an ISession instance with static methods of class CurrentSessionContext.
The configuration
<session-factory>
..
<property name="current_session_context_class">web</property>
</session-factory>
In the article you can check that we need at the app start initialize factory (just an extract):
public class WebApiApplication : System.Web.HttpApplication
{
private void InitializeSessionFactory() { ... }
protected void Application_Start()
{
InitializeSessionFactory();
...
Next we should create some AOP filter (just an extract):
public class NhSessionManagementAttribute : ActionFilterAttribute
{
...
public override void OnActionExecuting(HttpActionContext actionContext)
{
// init session
var session = SessionFactory.OpenSession();
...
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
// close session
...
session = CurrentSessionContext.Unbind(SessionFactory);
}
For more details check the source mentioned above
Your approach of passing the session to the constructor of the controller factory does not seems to be working, there are a few ways to do this
1. Using dependency injection
If you are using a dependency injection framework, you have to configure controller so that it's constructed per request, it should looks like this (I have used the code for Ninject)
Step 1 - setup the session for injection
public class DIModule : NinjectModule
{
public override void Load()
{
this.Bind<ISessionFactory>()... bind to the session factory
this.Bind<ISession>().ToMethod(ctx => ctx.Kernel.Get<ISessionFactory>().OpenSession())
.InRequestScope();
}
private ISession CreateSessionProxy(IContext ctx)
{
var session = (ISession)this.proxyGenerator.CreateInterfaceProxyWithoutTarget(typeof(ISession), new[] { typeof(ISessionImplementor) }, ctx.Kernel.Get<SessionInterceptor>());
return session;
}
}
Step 2 - Create the controller factory so that it will inject the session when resolving
public class NinjectControllerFactory : DefaultControllerFactory, IDependencyResolver
{
private IDependencyResolver _defaultResolver;
public NinjectControllerFactory(IDependencyResolver defaultResolver)
{
_defaultResolver = defaultResolver;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
return controllerType == null
? null
: (IController)DependencyKernel.Kernel.Get(controllerType);
}
public IDependencyScope BeginScope()
{
return this;
}
public object GetService(Type serviceType)
{
try
{
return DependencyKernel.Kernel.Get(serviceType);
}
catch (Exception)
{
return GetService(serviceType);
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
object item = DependencyKernel.Kernel.Get(serviceType);
return new List<object>() {item};
}
catch (Exception)
{
return GetServices(serviceType);
}
}
public void Dispose()
{
}
}
Step 3 - Register the controller factory
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
var factory = new NinjectControllerFactory(GlobalConfiguration.Configuration.DependencyResolver);
ControllerBuilder.Current.SetControllerFactory(factory);
GlobalConfiguration.Configuration.DependencyResolver = factory;
}
}
Now what will happen is that when your controller is created it will inject the a new NH session per each request.
2. Using a filter
This is much simpler, but you may need to change your controllers a bit this to work,
Step 1 - Setup the correct session context for the factory
_sessionFactory = CreateConfiguration()
.ExposeConfiguration(c => c.SetProperty("current_session_context_class","web"))
.BuildSessionFactory();
Step 2 - Create the filter
public class SessionPerRequestAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var session = SessionFactory.OpenSession();
NHibernate.Context.CurrentSessionContext.Bind(session);
base.OnActionExecuting(actionContext);
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var session = SessionFactory.GetCurrentSession();
session.Flush();
session.Clear();
session.Close();
base.OnActionExecuted(actionExecutedContext);
}
}
Step 3 - Register the filter in global configuration
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
//Do other config here
config.Filters.Add(new SessionPerRequestAttribute());
}
}
Step 4 - Modify your controller a bit,
public class CategoryController : ApiController
{
private readonly ICategoryMapper _categoryMapper;
private readonly IHttpCategoryFetcher _categoryFetcher;
public CategoryController(
ICategoryMapper categoryMapper,
IHttpCategoryFetcher categoryFetcher)
{
_categoryMapper = categoryMapper;
_categoryFetcher = categoryFetcher;
}
public IEnumerable<Category> Get()
{
var session = SessionFactory.GetCurrentSession();
return session
.QueryOver<Data.Model.Category>()
.List()
.Select(_categoryMapper.CreateCategory)
.ToList();
}
}
Here what happens is, when a request comes it will create a new session and it is bound to the request context and same is used for the web API method.

Resources