How to prevent my injected database from being disposed - c#

I have created a class, ObjectBuilder - I am injecting my dbContext into the class constructor and setting it to a read only attribute in the constructor method.
The class has a few different methods that use the dbContext, for example 'CreateorUpdateObject.
In my API controller I am instantiating the ObjectBuilder class. I am then trying to call the 'CreateorUpdateObject' method three times in a row. The first time everything works as intended. The second time, I get an ObjectDisposedException. I understand what this means. However I can't work out how to resolve this issue, seemingly executing a single method will always dispose the context - therefore none of the subsequent methods will work. I am not using any using clauses or disposing of the context myself. Can someone explain to me how to prevent dbContext from dispsoing so I can chain methods.
All the best!
Here is a snippet of the ObjectBuilder Class
class ObjectBuilder
{
readonly GuidObjectBuilder _guidObjectBuilder;
readonly projectviewerContext _db;
bool UpdatedGuidsArray { get; set; }
int UpdatedObjectCount { get; set; }
int CreatedObjectCount { get; set; }
ProjectObjects ActiveObject { get; set; }
public ObjectBuilder(GuidObjectBuilder guidObjectBuilder, projectviewerContext db)
{
this._guidObjectBuilder = guidObjectBuilder;
this._db = db;
this.UpdatedGuidsArray = false;
this.UpdatedObjectCount = 0;
this.CreatedObjectCount = 0;
}
public async Task<dynamic> CreateOrUpdateObject(string projectName, string tag, string pidClass, string guId, string fileName)
{
//SEND ONE ENTRY RETURNS A PROJECT_OBJECT MODEL
if (this._db == null) throw new ArgumentNullException("The object builder class has not been set a database. Set the object with a database");
try
{
//Check for an initial entry
List<ProjectObjects> matchingProjectObjects = (from data in this._db.ProjectObjects.ToList()
where data.ProjectName == projectName &&
data.Tag == tag
select data).ToList();
if (matchingProjectObjects.Any())
{
this.ActiveObject = this.UpdateProjectObject(matchingProjectObjects[0], pidClass, guId, fileName);
this._db.Update(this.ActiveObject);
this.UpdatedObjectCount++;
}
else
{
this.ActiveObject = this.CreateProjectObject(projectName, tag, pidClass, guId, fileName);
this._db.Add(this.ActiveObject);
this.CreatedObjectCount++;
}
await this._db.SaveChangesAsync();
if (this.UpdatedGuidsArray)
{
//Add new guid
await this._guidObjectBuilder.CreateOrUpdateUponModelOpen(this.ActiveObject.Id, guId, fileName);
}
this.UpdatedGuidsArray = false;
return this.ActiveObject;
}
catch (System.Exception error)
{
return error;
}
}
}
Here is a snippet of my test endpoint:
[HttpPost]
[Route("api/objectCreation/test1")]
public async Task<dynamic> TestOne()
{
try
{
projectviewerContext db = new projectviewerContext();
ObjectBuilder objectBuilder = new ObjectBuilder(new GuidObjectBuilder(db), db);
await objectBuilder.CreateOrUpdateObject("Project 1", "VV00011", "Gate Valve", "XXCCBBVVNNDDFFHH", "3D_Model.nwd");
await objectBuilder.CreateOrUpdateObject("Project 1", "VV00012", "Gate Valve", "XXFFGGHHIILLMMNN", "3D_Model.nwd");
await objectBuilder.CreateOrUpdateObject("Project 1", "VV00014", "Gate Valve", "123456789", "PID_drawing.nwd");
return "bang";
}
catch (System.Exception error)
{
return error.Message;
}
}

Related

How to unit test my EF repository method using Moq?

I'm attempting to write a unit test for my repository class for its Create method that uses DbContext and the Add method.
My idea was to get a count of the number of existing records. Call the Create method. Get the new count of records and check that its incremented by 1.
However, when running the unit test, it errors when calling the Add method with the following error:
{"Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.\r\nObject name: 'DbContext'."}
I'm trying to understand why is this and how to overcome this?
public class MyDatabaseContext : DbContext
{
public MyDatabaseContext(DbContextOptions<MyDatabaseContext> options) : base(options)
{
}
public DbSet<Record> Records { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Record>();
}
}
public class Repository : IRepository
{
private readonly MyDatabaseContext _dbContext;
public Repository(MyDatabaseContext dbContext)
{
_dbContext = dbContext;
}
public Record Create(Record record)
{
try
{
using (_dbContext)
{
var response = _dbContext.Records.Add(record); //erroring line
_dbContext.SaveChanges();
return response.Entity;
}
}
catch (Exception ex)
{
return null;
}
}
public IEnumerable<Record> GetAll()
{
try
{
using (_dbContext)
{
return _dbContext.Records.ToList();
}
}
catch (Exception ex)
{
return null;
}
}
}
public interface IRepository
{
Record Create(Record record);
IEnumerable<Record> GetAll();
}
Startup.cs:
services.AddDbContext<MyDatabaseContext>(opt => opt.UseInMemoryDatabase("memoryDb"));
services.AddScoped<IRepository, Repository>();
Unit test:
[TestMethod]
public async Task Create_Successfully()
{
var repository = new Repository(await GetDbContext());
var existingRecords = repository.GetAll();
repository.Create(new Record());
var newRecords = repository.GetAll();
Assert.AreEqual(3, existingRecords.Count());
Assert.AreEqual(4, newRecords.Count());
}
private async Task<DbContext> GetDbContext()
{
var options = new DbContextOptionsBuilder<DbContext>().UseInMemoryDatabase(Guid.NewGuid().ToString()).Options;
var context = new DbContext(options);
context.Database.EnsureCreated();
if (await context.Records.CountAsync() <= 0)
{
for (int i = 1; i <= 3; i++)
{
context.Records.Add(new Records());
await context.SaveChangesAsync();
}
}
return context;
}
You need to remove the using statements in the GetAll and Create methods:
public Record Create(Record record)
{
try
{
using (_dbContext)
{
var response = _dbContext.Records.Add(record); //erroring line
_dbContext.SaveChanges();
return response.Entity;
}
}
catch (Exception ex)
{
return null;
}
}
To:
public Record Create(Record record)
{
try
{
var response = _dbContext.Records.Add(record); //erroring line
_dbContext.SaveChanges();
return response.Entity;
}
catch (Exception ex)
{
return null;
}
}
You don't need to worry about disposing the service as the conatiner will do that for you in production. In your tests you can do this if you want to clean things up:
[TestMethod]
public async Task Create_Successfully()
{
using (var context = await GetDbContext())
{
var repository = new Repository(context);
var existingRecords = repository.GetAll();
repository.Create(new Record());
var newRecords = repository.GetAll();
Assert.AreEqual(3, existingRecords.Count());
Assert.AreEqual(4, newRecords.Count());
}
}

Updating an object asynchronously with another one

I'm trying to update an object with another object asynchronously. I'm trying to get the CustomerId value from Statues and then use it to call a specific customer and pass those values into PreviousStatuses. Then update the StatusToAdd with PreviousStatuses. If I pass Statues to StatusToAdd the values update. However, it's the wrong customer id. That's why I'm using PreviousStatuses.
This is the error I get:
crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: Object reference not set to an instance of an object.
System.NullReferenceException: Object reference not set to an instance of an object.
at DSPDRewrite.Pages.Popups.AddStatusComponent.UpdateValues(String id)
at DSPDRewrite.Pages.Popups.AddStatusComponent.OnInitializedAsync()
at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()
at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle)
[Parameter]
public int CustomerId { get; set; }
[CascadingParameter]
public Task<AuthenticationState> AuthState { get; set; }
public Status Statuses;
public Status PreviousStatuses;
//IList<Status> PreviousStatuses;
public Dspd1056Status StatusToAdd = new Dspd1056Status();
public Customer customer;
public int AccountStatusId = 0;
protected override async Task OnInitializedAsync()
{
Statuses = await dataService.Get1056StatusById(CustomerId);
//int id = Int32.Parse(Statuses.CustomerId);
// Statuses = await dataService.Get1056StatusById(id);
Console.WriteLine(Statuses.CustomerId);
await UpdateValues(Statuses.CustomerId);
}
async Task UpdateValues(string id)
{
PreviousStatuses = await dataService.Get1056StatusById(Int32.Parse((id)));
StatusToAdd.AccountCurrent = PreviousStatuses.AccountCurrent;
StatusToAdd.StartDate = PreviousStatuses.StartDate;
StatusToAdd.EndDate = PreviousStatuses.EndDate;
StatusToAdd.Units = PreviousStatuses.Units;
StatusToAdd.Ppc = PreviousStatuses.Ppc;
StatusToAdd.EndStatus = PreviousStatuses.EndStatus;
StatusToAdd.ContinuallyFunded = PreviousStatuses.ContinuallyFunded;
StatusToAdd.AnnualUnits = PreviousStatuses.AnnualUnits;
StatusToAdd.Elg = PreviousStatuses.Elg;
StatusToAdd.ReceiptDate = PreviousStatuses.ReceiptDate;
StatusToAdd.RahTripsFunded = PreviousStatuses.RahTripsFunded;
StatusToAdd.Rate = PreviousStatuses.Rate;
StatusToAdd.AccountTotal = PreviousStatuses.AccountTotal;
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
if (CustomerId != 0)
{
customer = await dataService.GetCustomerById((int)CustomerId);
StateHasChanged();
}
}
}
A few things to consider:
OnInitializedAsync
Can your .Get1056StatusById() method return null (e.g. if CustomerId is not found)? If so that appears to be the cause of the error: your code calls
await UpdateValues(Statuses.CustomerId);
That suggests Statuses is null. I would add a null check to this code to handle that case. Not sure why the Console.WriteLine didn't throw the null reference first, I assume the sample code didn't have it when the error was thrown.
A few other points: fields and methods in Components should normally be private or protected. If you are going to expose outside the Component they should be properties. Methods are rarely called outside a component. My suggested changes would be:
[Parameter] public int CustomerId { get; set; }
[CascadingParameter] public Task<AuthenticationState> AuthState { get; set; }
Status Statuses;
Status PreviousStatuses;
Dspd1056Status StatusToAdd = new Dspd1056Status();
Customer customer;
int AccountStatusId = 0;
protected override async Task OnInitializedAsync()
{
Statuses = await dataService.Get1056StatusById(CustomerId);
if(Statuses != null)
{
Console.WriteLine(Statuses.CustomerId);
await UpdateValues(Statuses.CustomerId);
}
}
async Task UpdateValues(string id)
{
PreviousStatuses = await dataService.Get1056StatusById(Int32.Parse((id)));
// rest...
Your component HTML should obviously check for a null Statuses before it tries to render:
#if(Statuses != null)
{
<p>Customer is #Statuses.CustomerId</p>
}
This is such a frequently used pattern in Blazor apps I usually use a <NotNull> component:
https://gist.github.com/conficient/eab57ade2587104d71ac6f26ddfd4865

how do I cache an output in ASP.NET Core

I have a API controller,and the scenario is:
I need to consume third party datasource(let's say the third party is provided as a dll file for simplicity, and the dll contain Student model and StudentDataSource that contain a lot of method to retrieve student ), and calling the third party data source is costly and data only gets updated every 6 hours.
so somehow I need to cache the output, below is some action method from my api controller:
// api controller that contain action methods below
[HttpGet]
public JsonResult GetAllStudentRecords()
{
var dataSource = new StudentDataSource();
return Json(dataSource.GetAllStudents());
}
[HttpGet("{id}")]
public JsonResult GetStudent(int id)
{
var dataSource = new StudentDataSource();
return Json(dataSource.getStudent(id));
}
then how should I cache the result especially for the second action method, it is dumb to cache every student result with different id
My team is implementing a similar caching strategy on an API controller using a custom Action filter attribute to handle the caching logic. See here for more info on Action filters.
The Action filter's OnActionExecuting method runs prior to your controller method, so you can check whether the data you're looking for is already cached and return it directly from here, bypassing the call to your third party datasource when cached data exists. We also use this method to check the type of request and reset the cache on updates and deletes, but it sounds like you won't be modifying data.
The Action filter's OnActionExecuted method runs immediately AFTER your controller method logic, giving you an opportunity to cache the response object before returning it to the client.
The specifics of how you implement the actual caching are harder to provide an answer for, but Microsoft provides some options for in-memory caching in .NET Core (see MemoryCache.Default not available in .NET Core?)
I used the solution with the cache strategy through the controller API as #chris-brenberg pointed out, it turned out like this
on controller class
[ServerResponseCache(false)]
[HttpGet]
[Route("cache")]
public ActionResult GetCache(string? dateFormat) {
Logger.LogInformation("Getting current datetime");
return Ok(new { date = DateTime.Now.ToString() });
}
on ServerResponseCacheAttribute.cs
namespace Site.Api.Filters {
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Primitives;
using System.Globalization;
using System.Threading.Tasks;
public class ServerResponseCacheAttribute : TypeFilterAttribute {
public ServerResponseCacheAttribute(bool byUserContext = true) : base(typeof(ServerResponseCacheAttributeImplementation)) =>
Arguments = new object[] { new ServerResponseCacheProps { ByUserContext = byUserContext } };
public ServerResponseCacheAttribute(int secondsTimeout, bool byUserContext = true) : base(typeof(ServerResponseCacheAttributeImplementation)) =>
Arguments = new object[] { new ServerResponseCacheProps { SecondsTimeout = secondsTimeout, ByUserContext = byUserContext } };
public class ServerResponseCacheProps {
public int? SecondsTimeout { get; set; }
public bool ByUserContext { get; set; }
}
public class ServerResponseCacheConfig {
public bool Disabled { get; set; }
public int SecondsTimeout { get; set; } = 60;
public string[] HeadersOnCache { get; set; } = { "Accept-Language" };
}
private class ServerResponseCacheAttributeImplementation : IAsyncActionFilter {
private string _cacheKey = default;
readonly ILogger<ServerResponseCacheAttributeImplementation> _logger;
readonly IMemoryCache _memoryCache;
readonly ServerResponseCacheConfig _config;
readonly bool _byUserContext;
public ServerResponseCacheAttributeImplementation(ILogger<ServerResponseCacheAttributeImplementation> logger,
IMemoryCache memoryCache, ServerResponseCacheProps props) {
_logger = logger;
_memoryCache = memoryCache;
_byUserContext = props.ByUserContext;
_config = new ServerResponseCacheConfig {
SecondsTimeout = props.SecondsTimeout ?? 60,
HeadersOnCache = new[] { "Accept-Language" }
};
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) {
if (context == null) {
throw new ArgumentNullException(nameof(context));
}
if (next == null) {
throw new ArgumentNullException(nameof(next));
}
if (_config.Disabled) {
await next();
return;
}
OnActionExecutingAsync(context);
if (context.Result == null) {
OnActionExecuted(await next());
}
}
void OnActionExecutingAsync(ActionExecutingContext context) {
SetCacheKey(context.HttpContext.Request);
// Not use a stored response to satisfy the request. Will regenerates the response for the client, and updates the stored response in its cache.
bool noCache = context.HttpContext.Request.Headers.CacheControl.Contains("no-cache");
if (noCache) {
return;
}
TryLoadResultFromCache(context);
}
void SetCacheKey(HttpRequest request) {
if (request == null) {
throw new ArgumentException(nameof(request));
}
if (!string.Equals(request.Method, "GET", StringComparison.InvariantCultureIgnoreCase)) {
return;
}
List<string> cacheKeys = new List<string>();
if (_byUserContext && request.HttpContext.User.Identity.IsAuthenticated) {
cacheKeys.Add($"{request.HttpContext.User.Identity.Name}");
}
string uri = UriHelper.BuildAbsolute(request.Scheme, request.Host, request.PathBase, request.Path, request.QueryString);
cacheKeys.Add(uri);
foreach (string headerKey in _config.HeadersOnCache) {
StringValues headerValue;
if (request.Headers.TryGetValue(headerKey, out headerValue)) {
cacheKeys.Add($"{headerKey}:{headerValue}");
}
}
_cacheKey = string.Join('_', cacheKeys).ToLower();
}
void TryLoadResultFromCache(ActionExecutingContext context) {
ResultCache resultCache;
if (_cacheKey != null && _memoryCache.TryGetValue(_cacheKey, out resultCache)) {
_logger.LogInformation("ServerResponseCache: Response loaded from cache, cacheKey: {cacheKey}, expires at: {expiration}.", _cacheKey, resultCache.Expiration);
context.Result = resultCache.Result;
SetExpiresHeader(context.HttpContext.Response, resultCache.Expiration);
}
}
/// <summary>Add expires header (the time after which the response is considered stale).</summary>
void SetExpiresHeader(HttpResponse response, DateTimeOffset expiration) {
string expireHttpDate = expiration.UtcDateTime.ToString("ddd, dd MMM yyyy HH:mm:ss", CultureInfo.InvariantCulture);
response.Headers.Add("Expires", $"{expireHttpDate} GMT");
}
void OnActionExecuted(ActionExecutedContext context) {
if (_cacheKey == null) {
return;
}
if (context.Result != null) {
DateTimeOffset expiration = SetCache(context.Result);
SetExpiresHeader(context.HttpContext.Response, expiration);
} else {
RemoveCache();
}
}
DateTimeOffset SetCache(IActionResult result) {
DateTimeOffset absoluteExpiration = DateTimeOffset.Now.AddSeconds(_config.SecondsTimeout);
ResultCache resultCache = new ResultCache {
Result = result,
Expiration = absoluteExpiration
};
_memoryCache.Set(_cacheKey, resultCache, absoluteExpiration);
_logger.LogInformation("ServerResponseCache: Response set on cache, cacheKey: {cacheKey}, until: {expiration}.", _cacheKey, absoluteExpiration);
return absoluteExpiration;
}
void RemoveCache() {
_memoryCache.Remove(_cacheKey);
_logger.LogInformation("ServerResponseCache: Response removed from cache, cacheKey: {cacheKey}.", _cacheKey);
}
}
private class ResultCache {
public IActionResult Result { get; set; }
public DateTimeOffset Expiration { get; set; }
}
}}
I hope it helps someone, best regards

How do I use async Task<IActionResult> ? Or How to run in async way in my Asp.Net Core Web Api

I'am trying to run my Controller Action in async way.
How do I use async Task ? Or How to run in async way
// Db context
public class DeptContext : DbContext
{
public LagerContext(DbContextOptions<LagerContext> options)
: base(options)
{
Database.Migrate();
}
public DbSet<Department> Departments { get; set; }
public DbSet<Product> Products { get; set; }
}
// This is my Interface IDepRepository
Task<Department> GetDepartmentWithOrWithoutProducts(int deptId, bool includeProducts);
// And my Repository class DepRepository
public class DepRepository : IDepRepository
{
private DeptContext db;
public DepRepository(DeptContext context)
{
db = context;
}
// I'am geting Department name with products or Without products
public async Task<Department> GetDepartmentWithOrWithoutProducts(int deptId, bool includeProducts)
{
if(includeProductss)
{
return await db.Departments.Include(c => c.Products).Where(s => s.deptId == deptId).SingleAsync();
}
return await db.Departments.Where(s => s.deptId == deptId).SingleAsync();
}
}
So How should I do now in my Controller to do it as async way: I tried as following but I don't know if it's right to do like this following:
I'm not getting any error but I don't if it's right way ...
using System.Threading.Tasks;
using System.Net;
using Microsoft.Data.Entity;
using Microsoft.EntityFrameworkCore;
[Route("api/departments")]
public class DepartmentsController : Controller
{
private IDeptRepository _deptInfoRepository;
public DepartmentsController(IDeptRepository deptInfoRepository)
{
_deptInfoRepository = deptInfoRepository;
}
[HttpGet("{id}")]
public async Task<IActionResult> GetDepatment(int id, bool includeProducts = false)
{
var dept = _deptInfoRepository.GetDepartmentWithOrWithoutProducts(id, includeComputers);
if(dept == null)
{
return BadRequest();
}
if(includeProducts)
{
var depResult = new DepartmentDto() { deptId = dept.deptId, deptName = dept.deptName };
foreach(var department in dept.Products)
{
depResult.Products.Add(new ProductDto() { productId = department.productId, deptId = department.deptId, ProductName = department.ProductName });
}
return Ok(depResult);
}
var departmentWithoutProductResult = new DepartmentsWithoutProductsDto() { DeptId = dept.deptId, DeptName = dept.DeptName};
return Ok(departmentWithoutProductResult);
}
How do I do to get my controller in async way.. I don't know where to put those await and ToListAsync(). Thank you in advance!
The interface should be renamed to better show the intent.
public interface IDepRepository {
Task<Department> GetDepartmentWithOrWithoutProductsAsync(int deptId, bool includeProducts);
//...
}
Which would update the implementation accordingly. Since the method is not actually using anything after the async call then there not really any reason to tag the method as async. Just return the Task.
public Task<Department> GetDepartmentWithOrWithoutProductsAsync(int deptId, bool includeProducts) {
if(includeProductss) {
return db.Departments.Include(c => c.Products).Where(s => s.deptId == deptId).SingleAsync();
}
return db.Departments.Where(s => s.deptId == deptId).SingleAsync();
}
The controller action however needs to await the task and then continue after the task has completed so therefore that method will be tagged with async.
[HttpGet("{id}")]
public async Task<IActionResult> GetDepatment(int id, bool includeProducts = false) {
var dept = await _deptInfoRepository.GetDepartmentWithOrWithoutProductsAsync(id, includeComputers);
if (dept == null) {
return BadRequest();
}
if (includeProducts) {
var depResult = new DepartmentDto() { deptId = dept.deptId, deptName = dept.deptName };
foreach (var department in dept.Products) {
depResult.Products.Add(new ProductDto() {
productId = department.productId,
deptId = department.deptId,
ProductName = department.ProductName
});
}
return Ok(depResult);
}
var departmentWithoutProductResult = new DepartmentsWithoutProductsDto() { DeptId = dept.deptId, DeptName = dept.DeptName};
return Ok(departmentWithoutProductResult);
}
What I can't tell from your code is the datatype of what GetDepartments returns. My guess is that you are using EF Core and GetDepartments returns a DbSet or a LINQ query against a DbSet. If that is the case, then after the line where your depEntities variable is set, that variable points to a deferred object (an expression tree that has not been evaulated yet). Or in other words, the actual query has not been sent to the database yet. When you loop over the depEntities (with your foreach loop), you are causing the actual potentially long-running work to occur (database access). That's what you want to await on. So, yes, you could make an async version of GetDepartments or you could also probably change your code to be:
var depEntities = await _depRepository.GetDepartments().ToListAsync();
The call to ToListAsync will enumerate the deferred object and perform the database access. Your return statement would just return results. Behind the scenes, the method actually returns on your await statement and resumes after the work you're awaiting on completes.
One last note.. any database exceptions will occur at the point where the deferred object is enumerated.
You should not do any await on already-prepared results list. It's already contain required data - what you want to wait to?
You should make new async version of your GetDepartments() method and await while obtaining data from repository:
var depEntities = await _depRepository.GetDepartmentsAsync();

Validate fails in unit tests

I am running a unit test of my PostMyModel route. However, within PostMyModel() I used the line Validate<MyModel>(model) to revalidate my model after it is changed. I am using a test context, so as not to be dependent on the db for the unit tests. I have posted the test context and post method below:
Test Context
class TestAppContext : APIContextInterface
{
public DbSet<MyModel> MyModel { get; set; }
public TestAppContext()
{
this.MyModels = new TestMyModelDbSet();
}
public int SaveChanges(){
return 0;
}
public void MarkAsModified(Object item) {
}
public void Dispose() { }
}
Post Method
[Route(""), ResponseType(typeof(MyModel))]
public IHttpActionResult PostMyModel(MyModel model)
{
//Save model in DB
model.status = "Waiting";
ModelState.Clear();
Validate<MyModel>(model);
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.MyModels.Add(model);
try
{
db.SaveChanges();
}
catch (DbUpdateException)
{
if (MyModelExists(model.id))
{
return Conflict();
}
else
{
throw;
}
}
return CreatedAtRoute("DisplayMyModel", new { id = model.id }, model);
}
When the Validate<MyModel>(model) line runs, I get the error :
System.InvalidOperationException: ApiController.Configuration must not be null.
How can I correct this?
In order for the Validate command to run, there must be mock HttpRequest associated with the controller. The code to do this is below. This will mock a default HttpRequest, which is fairly unused in this case, allowing the method to be unit tested.
HttpConfiguration configuration = new HttpConfiguration();
HttpRequestMessage request = new HttpRequestMessage();
controller.Request = request;
controller.Request.Properties["MS_HttpConfiguration"] = configuration;

Categories