I have a controller the beginning of which looks like this:
[Route("api/[controller]")]
public class PersonsController : BaseController
BaseController looks like this so far:
public class BaseController : Controller
{
public BaseController(CompanyDbContext dbContext)
{
Db = dbContext;
}
protected CompanyDbContext Db;
}
PersonsController has a few gets, a post, a put, and a delete. Everything except the Delete action works fine, there are no problems resolving the injected CompanyDbContext.
The Delete action looks like this:
[HttpDelete("{id}")]
public async Task<IActionResult> Delete(int id)
{
var pers = await Db.Persons.SingleOrDefaultAsync(p => p.PersonId == id);
if (pers == null)
{
return NotFound();
}
Db.Remove(pers);
await Db.SaveChangesAsync();
return Ok();
}
Yet when I do a delete request:
public async Task DeletePersonAsync(int id)
{
var resp = await _client.DeleteAsync($"api/Persons/{id}");
resp.EnsureSuccessStatusCode();
}
where _client is an HttpClient, I get the following error:
InvalidOperationException: Unable to resolve service for type
'AcmeSoft.Api.Data.CompanyDbContext' while attempting to activate
'AcmeSoft.Api.Controllers.PersonsController'
I am using the default, built-in DI that comes with a new MVC Core 2.0 project. I register the context service in class Startup as follows:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<CompanyDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddMvc();
}
Yet the service resolves properly for all actions but Delete. What could be wrong here? Where have I gone wrong?
For those that like long questions, the entire PersonsController is as follows:
[Route("api/[controller]")]
public class PersonsController : BaseController
{
public PersonsController(CompanyDbContext dbContext) : base(dbContext)
{
}
[HttpGet]
public IActionResult Get()
{
var persons = Db.Persons.ToList();
return Ok(persons);
}
[HttpGet("{id}")]
public async Task<IActionResult> Get(int id)
{
var pers = await Db.Persons.SingleOrDefaultAsync(p => p.PersonId == id);
if (pers == null)
{
return Ok(null);
}
return Ok(pers);
}
[HttpGet("GetByIdNumber/{idNumber}")]
public async Task<IActionResult> GetByIdNumber(string idNumber)
{
var pers = await Db.Persons.SingleOrDefaultAsync(e => e.IdNumber == idNumber);
if (pers == null)
{
return Ok(null);
}
return Ok(pers);
}
[HttpGet("PersonEmployees")]
public async Task<IActionResult> PersonEmployees()
{
var emps = await Db.PersonEmployees.ToListAsync();
return Ok(emps);
}
[HttpPost]
public async Task<IActionResult> Post([FromBody] Person person)
{
Db.Add(person);
await Db.SaveChangesAsync();
return Ok(person);
}
[HttpPut]
public async Task<IActionResult> Put([FromBody] Person person)
{
Db.Update(person);
await Db.SaveChangesAsync();
return Ok(person);
}
[HttpDelete("{id}")]
public async Task<IActionResult> Delete(int id)
{
var pers = await Db.Persons.SingleOrDefaultAsync(p => p.PersonId == id);
if (pers == null)
{
return NotFound();
}
Db.Remove(pers);
await Db.SaveChangesAsync();
return Ok();
}
}
All actions except delete work.
ADDED: The stack trace shown on the developer error page is:
System.InvalidOperationException: Unable to resolve service for type 'AcmeSoft.Api.Data.CompanyDbContext' while attempting to activate 'AcmeSoft.Api.Controllers.PersonsController'.
at Microsoft.Extensions.Internal.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
at lambda_method(Closure , IServiceProvider , Object[] )
at Microsoft.AspNetCore.Mvc.Controllers.ControllerActivatorProvider.<>c__DisplayClass4_0.<CreateActivator>b__0(ControllerContext controllerContext)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.<CreateControllerFactory>g__CreateController|0(ControllerContext controllerContext)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeInnerFilterAsync>d__14.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeNextResourceFilter>d__22.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeFilterPipelineAsync>d__17.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeAsync>d__15.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Builder.RouterMiddleware.<Invoke>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.<Invoke>d__7.MoveNext()
Related
I am having an issue with the following code, now I understand what the problem is but I don't have a solution to make the code do what I want.
// POST: api/Airports
[HttpPost]
public async Task<ActionResult<Airport>> CreateAirport(AirportCreateDto airportCreateDto)
{
var airportModel = _mapper.Map<Airport>(airportCreateDto);
_repository.CreateAirport(airportModel);
await _repository.SaveChanges();
var airportReadDto = _mapper.Map<AirportReadDto>(airportModel);
return CreatedAtRoute(nameof(GetAirport), new { airportReadDto.ID }, airportReadDto);
}
The CreatedAtRoute() method is the issue. Now, GetAirport is of type Task<ActionResult> which is probably the cause of the problem.
Here's the error
System.InvalidOperationException: No route matches the supplied values.
at Microsoft.AspNetCore.Mvc.CreatedAtRouteResult.OnFormatting(ActionContext context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor.ExecuteAsyncCore(ActionContext
context, ObjectResult result, Type objectType, Object value)
at Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor.ExecuteAsync(ActionContext context,
ObjectResult result)
at Microsoft.AspNetCore.Mvc.ObjectResult.ExecuteResultAsync(ActionContext context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultAsync(IActionResult result)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State&
next, Scope& scope, Object& state, Boolean& isCompleted)
at
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeNextResultFilterAsync[TFilter,
TFilterAsync
]()
Is there a solution where I can keep using CreatedAtRoute() and GetAirport of type Task<ActionResult>?
Here's the code for GetAirport
// GET: api/Airports/5
[HttpGet("{id}")]
public async Task<ActionResult<Airport>> GetAirport(int id)
{
var airport = await _repository.GetAirportById(id);
if (airport == null)
{
return NotFound();
}
return Ok(_mapper.Map<AirportReadDto>(airport.Value));
}
System.InvalidOperationException: No route matches the supplied values.
You can try to explicitly set route name as below, which works for me.
[HttpGet("{id}", Name = "GetAirport")]
public async Task<ActionResult> GetAirport()
{
//...
Action method CreateAirport
[HttpPost]
public async Task<ActionResult<Airport>> CreateAirport(AirportCreateDto airportCreateDto)
{
//...
return CreatedAtRoute(nameof(GetAirport), new { id = airportReadDto.ID }, airportReadDto);
}
Test Result
I am facing method not found error in web server, but locally in visual studio it works:
[HttpGet]
[Route("api/checkhealth")]
public async Task<IHttpActionResult> CheckHealth()
{
var message = "checkhealth method was invoked";
return new TextResult(message, Request);
}
Then in browser getting below error:
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>Method not found: 'System.Net.Http.HttpRequestMessage System.Web.Http.ApiController.get_Request()'.
</ExceptionMessage>
<ExceptionType>System.MissingMethodException</ExceptionType>
<StackTrace>at BMI.Controllers.APIController.<CheckHealth>d__0.MoveNext() at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start[TStateMachine](TStateMachine& stateMachine) at BMI.Controllers.APIController.CheckHealth() at lambda_method(Closure , Object , Object[] ) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass6_3.<GetExecutor>b__2(Object instance, Object[] methodParameters) at
System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken) --- End of stack trace from previous location where exception was thrown --- at
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Controllers.ApiControllerActionInvoker.
<InvokeActionAsyncCore>d__1.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Controllers.ActionFilterResult.
<ExecuteAsync>d__5.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Dispatcher.HttpControllerDispatcher.
<SendAsync>d__15.MoveNext()
</StackTrace>
</Error>
I have implemented IHttpActionResult as below:
public class TextResult : IHttpActionResult
{
string message;
HttpRequestMessage request;
public TextResult(string message, HttpRequestMessage request)
{
this.message = message;
this.request = request;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = new HttpResponseMessage()
{
Content = new StringContent(message),
RequestMessage = request
};
return Task.FromResult(response);
}
}
The actual method in my project is post but here I am trying to fix with get first then I believe post will also work.
Here to mention the below method work perfectly, so I think something I am missing with IHttpActionResult:
[HttpGet]
[Route("api/getok")]
public JsonResult<string> getJson()
{
return Json("OK");
}
Do you have any one faced and solved this problem yet. Please help me, thanks in advance.
Using the CreateResponse extension on the request would allow any configuration from the request to be copied over to the response which would probably be missing when you create the response manually like in your example.
public class TextResult : IHttpActionResult {
string message;
HttpRequestMessage request;
public TextResult(string message, HttpRequestMessage request) {
this.message = message;
this.request = request;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken) {
var response = request.CreateResponse(HttpStatusCode.OK, message);
return Task.FromResult(response);
}
}
Also the controller action is not defined correctly as it is defined as async Task<IHttpActionResult> when the action is not doing anything async.
Refactor to follow correct syntax if not actually asynchronous.
[HttpGet]
[Route("api/checkhealth")]
public IHttpActionResult CheckHealth() {
var message = "checkhealth method was invoked";
return new TextResult(message, Request);
}
Hello I need to test my APIcontroller which implements ApiController and I don't know how to do this, I know basics of UnitTesting but this is a little bit too complex for me. Also I don't know how to use automapper in unit tests, so maybe someone could help me with this
Here is my controller:
namespace Vidly.Controllers.Api
{
public class CustomersController : ApiController
{
private ApplicationDbContext _context;
public CustomersController(ApplicationDbContext _context)
{
_context = new ApplicationDbContext();
}
// GET /api/customers
public IHttpActionResult GetCustomers(string query = null)
{
var customersQuery = _context.Customers
.Include(c => c.MembershipType);
if (!String.IsNullOrWhiteSpace(query))
customersQuery = customersQuery.Where(c => c.Name.Contains(query));
var customerDtos = customersQuery
.ToList()
.Select(Mapper.Map<Customer, CustomerDto>);
return Ok(customerDtos);
}
// GET /api/customers/1
public IHttpActionResult GetCustomer(int id)
{
var customer = _context.Customers.SingleOrDefault(c => c.Id == id);
if (customer == null)
return NotFound();
return Ok(Mapper.Map<Customer, CustomerDto>(customer));
}
// POST /api/customers
[HttpPost]
public IHttpActionResult CreateCustomer(CustomerDto customerDto)
{
if (!ModelState.IsValid)
return BadRequest();
var customer = Mapper.Map<CustomerDto, Customer>(customerDto);
_context.Customers.Add(customer);
_context.SaveChanges();
customerDto.Id = customer.Id;
return Created(new Uri(Request.RequestUri + "/" + customer.Id), customerDto);
}
// PUT /api/customers/1
[HttpPut]
public IHttpActionResult UpdateCustomer(int id, CustomerDto customerDto)
{
if (!ModelState.IsValid)
return BadRequest();
var customerInDb = _context.Customers.SingleOrDefault(c => c.Id == id);
if (customerInDb == null)
return NotFound();
Mapper.Map(customerDto, customerInDb);
_context.SaveChanges();
return Ok();
}
// DELETE /api/customers/1
[HttpDelete]
public IHttpActionResult DeleteCustomer(int id)
{
var customerInDb = _context.Customers.SingleOrDefault(c => c.Id == id);
if (customerInDb == null)
return NotFound();
_context.Customers.Remove(customerInDb);
_context.SaveChanges();
return Ok();
}
}
}
So how do I need to start, do I need some kind of interface like this to mock dbcontext:
public interface IAPICustomerRepository
{
IHttpActionResult GetCustomers(string query = null);
IHttpActionResult GetCustomer(int id);
IHttpActionResult CreateCustomer(CustomerDto customerDto);
IHttpActionResult UpdateCustomer(int id, CustomerDto customerDto);
IHttpActionResult DeleteCustomer(int id);
}
Or maybe I can write Unit tests without mocking.
UPDATE
After I edited my code with Nkosi's suggestion I am getting these errors
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
An error occurred when trying to create a controller of type 'CustomersController'. Make sure that the controller has a parameterless public constructor.
</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
<StackTrace>
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType) at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()
</StackTrace>
<InnerException>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Type 'Vidly.Controllers.Api.CustomersController' does not have a default constructor
</ExceptionMessage>
<ExceptionType>System.ArgumentException</ExceptionType>
<StackTrace>
at System.Linq.Expressions.Expression.New(Type type)
at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
</StackTrace>
</InnerException>
</Error>
Then I create a default constructor (without parameters as I understand) and then I get another error:
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Object reference not set to an instance of an object.
</ExceptionMessage>
<ExceptionType>System.NullReferenceException</ExceptionType>
<StackTrace>
at Vidly.Controllers.Api.CustomersController.GetCustomers(String query) in C:\Users\Dovydas Petrutis\Desktop\vidly-mvc-5-master\Vidly\Controllers\Api\CustomersController.cs:line 26
at lambda_method(Closure , Object , Object[] )
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[]
methodParameters) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments)
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken) --- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext() --- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext() --- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Dispatcher.HttpControllerDispatcher <SendAsync>d__1.MoveNext()
</StackTrace>
</Error>
Where could be the problem now?
First create a service that exposes the functionality you want so that it can be easily replaced/mocked for testing and improve maintainability.
You were close when you mentioned the repository. IHttpActionResult is a UI concern so you can refactor your interface like this.
public interface IAPICustomerRepository {
IEnumerable<CustomerDto> GetCustomers(string query = null);
CustomerDto GetCustomer(int id);
int CreateCustomer(CustomerDto customerDto);
CustomerDto UpdateCustomer(int id, CustomerDto customerDto);
bool? DeleteCustomer(int id);
}
The controller will now be slimmer in terms of functionality and no longer cares about EF/DbContext or Automapper.
public class CustomersController : ApiController {
private IAPICustomerRepository repository;
public CustomersController(IAPICustomerRepository repository) {
this.repository = repository;
}
// GET /api/customers
public IHttpActionResult GetCustomers(string query = null) {
var customerDtos = repository.GetCustomers(query);
return Ok(customerDtos);
}
// GET /api/customers/1
public IHttpActionResult GetCustomer(int id) {
var customer = repository.GetCustomer(id);
if (customer == null)
return NotFound();
return Ok(customer);
}
// POST /api/customers
[HttpPost]
public IHttpActionResult CreateCustomer([FromBody]CustomerDto customerDto) {
if (!ModelState.IsValid)
return BadRequest();
var id = repository.CreateCustomer(customerDto);
customerDto.Id = id;
return Created(new Uri(Request.RequestUri + "/" + id), customerDto);
}
// PUT /api/customers/1
[HttpPut]
public IHttpActionResult UpdateCustomer(int id, [FromBody]CustomerDto customerDto) {
if (!ModelState.IsValid)
return BadRequest();
var updated = repository.UpdateCustomer(id, customerDto);
if (updated == null)
return NotFound();
return Ok();
}
// DELETE /api/customers/1
[HttpDelete]
public IHttpActionResult DeleteCustomer(int id) {
var deleted = repository.DeleteCustomer(id);
if (deleted == null)
return NotFound();
return Ok();
}
}
With the controller now dependent on an abstraction you can mock the functionality when testing the controller in isolation.
Automapper is an implementation concern that can be encapsulated behind the abstraction so that it is a non issue when testing.
The following example uses Moq mocking framework. You can use your framework of choice is you so choose.
[TestClass]
public class CustomersController_Should {
[TestMethod]
public void GetCustomers() {
//Arrange
var fakeCustomers = new List<CustomerDto>{
new CustomerDto{ Id = 1 }
};
var repository = new Mock<IAPICustomerRepository>();
repository
.Setup(_ => _.GetCustomers(It.IsAny<string>()))
.Returns(fakeCustomers)
.Verifiable();
var controller = new CustomersController(repository.Object);
//Act
var result = controller.GetCustomers();
//Assert
repository.Verify();
//..other assertions
}
//...Other tests
}
The functionality that was originally in the controller would be encapsulated in the implementation of the repository in production.
I have a controller.
public sealed class AccountsController : BaseApiController
{
private readonly IDatabaseAdapter _databaseAdapter;
public AccountsController(IDatabaseAdapter databaseAdapter)
{
_databaseAdapter = databaseAdapter;
}
[AllowAnonymous]
[Route("create")]
public async Task<IHttpActionResult> CreateUser(CreateUserBindingModel createUserModel)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
if (! await _databaseAdapter.DoesAgentExist(createUserModel.UserName))
return BadRequest();
if (await _databaseAdapter.DoesAgentHaveAccount(createUserModel.UserName))
return BadRequest();
// Create account.
var password = PasswordHelper.GeneratePassword(32);
createUserModel.Password = password;
createUserModel.ConfirmPassword = password;
var user = new ApplicationUser
{
UserName = createUserModel.UserName,
};
var addUserResult = await AppUserManager.CreateAsync(user, createUserModel.Password);
if (!addUserResult.Succeeded)
return GetErrorResult(addUserResult);
var locationHeader = new Uri(Url.Link("GetUserById", new { id = user.Id }));
return Created(locationHeader, ModelFactory.Create(user));
}
}
When I send the following fiddler to the create method.
http://localhost:59430/api/accounts/create User-Agent: Fiddler
Content-Type: application/json Accept: application/json Host:
localhost:59430 Content-Length: 106
{ "UserName":"a.xxxxx", "Password":"xxxxxx",
"ConfirmPassword":"xxxxxx", }
It gets down to the following line:
var addUserResult = await AppUserManager.CreateAsync(user, createUserModel.Password);
Then the following exception occurs
{ "message": "An error has occurred.", "exceptionMessage": "Method
not found: 'System.Net.Http.HttpRequestMessage
System.Web.Http.ApiController.get_Request()'.", "exceptionType":
"System.MissingMethodException", "stackTrace": " at
WebAuth.Controllers.BaseApiController.get_AppUserManager()\r\n at
WebAuth.Controllers.AccountsController.d__3.MoveNext() in
C:\Users\stuarts\Documents\Visual Studio
2017\Projects\WebAuth\WebAuth\Controllers\AccountsController.cs:line
76\r\n--- End of stack trace from previous location where exception
was thrown ---\r\n at
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task)\r\n at
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task)\r\n at
System.Threading.Tasks.TaskHelpersExtensions.d__3`1.MoveNext()\r\n---
End of stack trace from previous location where exception was thrown
---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task)\r\n at
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task)\r\n at
System.Web.Http.Controllers.ApiControllerActionInvoker.d__0.MoveNext()\r\n---
End of stack trace from previous location where exception was thrown
---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task)\r\n at
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task)\r\n at
System.Web.Http.Controllers.ActionFilterResult.d__2.MoveNext()\r\n---
End of stack trace from previous location where exception was thrown
---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task)\r\n at
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task)\r\n at
System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()"
}
Anyone know what is going on? I have no idea why it can't find that method.
My bin folders contains
System.Web.Http.dll
System.Web.Http.Owin.dll
System.Net.Http.dll
ApplicationUserManager
public sealed class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store) : base(store)
{
}
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options,
IOwinContext context)
{
var appDbContext = context.Get<ApplicationDbContext>();
var appUserManager = new ApplicationUserManager(new UserStore<ApplicationUser>(appDbContext));
appUserManager.UserValidator = new UserValidator<ApplicationUser>(appUserManager)
{
AllowOnlyAlphanumericUserNames = true,
RequireUniqueEmail = false,
};
appUserManager.PasswordValidator = new PasswordValidator
{
RequiredLength = 12,
RequireNonLetterOrDigit = true,
RequireUppercase = true,
RequireLowercase = true,
RequireDigit = true
};
appUserManager.MaxFailedAccessAttemptsBeforeLockout = 3;
appUserManager.DefaultAccountLockoutTimeSpan = TimeSpan.FromHours(1);
return appUserManager;
}
}
BaseApiController
public class BaseApiController : ApiController
{
private ModelFactory _modelFactory;
private readonly ApplicationUserManager _applicationUserManager = null;
protected ApplicationUserManager AppUserManager => _applicationUserManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
protected ModelFactory ModelFactory => _modelFactory ?? (_modelFactory = new ModelFactory(Request, AppUserManager));
protected IHttpActionResult GetErrorResult(IdentityResult result)
{
if (result == null)
return InternalServerError();
if (result.Succeeded) return null;
if (result.Errors != null)
foreach (var error in result.Errors)
ModelState.AddModelError(string.Empty, error);
if (ModelState.IsValid)
return BadRequest();
return BadRequest(ModelState);
}
private readonly ApplicationRoleManager _appRoleManager = null;
protected ApplicationRoleManager AppRoleManager => _appRoleManager ?? Request.GetOwinContext().GetUserManager<ApplicationRoleManager>();
}
I found a solution to this.
When I was building there was build warnings going to the output window but not showing in the main error / warning window.
They were to do with assembly conflicts and said recommend putting the assembly redirect in the web.Config.
Once I had went through them all (around 80) it now works.
e.g.
<dependentAssembly>
<assemblyIdentity name="System.Net.Http" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
</dependentAssembly>
i have a problem in a new web api controller when i try to use EF5 with Oracle.
My controller:
public class DeviceV1Controller : ApiController
{
private readonly IDevice _repository;
public DeviceV1Controller()
{
IDevice _repository = new EFDeviceRepository();
}
[Route("api/Device/{hashImei}/app/{nome}")]
public HttpResponseMessage Post(string hashImei, string nome, [FromBody] DeviceInfo deviceInfo)
{
_repository.Add(deviceInfo);
return Request.CreateResponse(HttpStatusCode.OK);
}
}
_repository is correctly bound in the constructor, but entering the Post api this variable become null and i get this error:
{
message: "An error has occurred."
exceptionMessage: "object reference not set to an instance of an object."
exceptionType: "System.NullReferenceException"
stackTrace: " in MpssApiRest.Controllers.DeviceV1Controller.Post(String hashImei, String nome, DeviceInfo deviceInfo) in c:\SVILUPPO\MpssApiRest\MpssApiRest\MpssApiRest\Controllers\DeviceV1Controller.cs:riga 28 in lambda_method(Closure , Object , Object[] ) in System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters) in System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments) in System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken) --- Fine traccia dello stack da posizione precedente dove è stata generata l'eccezione --- in System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) in System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) in System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext() --- Fine traccia dello stack da posizione precedente dove è stata generata l'eccezione --- in System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) in System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) in System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext() --- Fine traccia dello stack da posizione precedente dove è stata generata l'eccezione --- in System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) in System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) in System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__0.MoveNext()"
}
EFDeviceRepository concrete class is:
public class EFDeviceRepository : IDevice
{
private readonly EntityDevice ctx;
public EFDeviceRepository()
{
ctx = new EntityDevice();
}
public void Add(Models.V1.DeviceInfo deviceInfo)
{
EntityDevice ctx = new EntityDevice();
MPSS_APP_DEVICE device = new MPSS_APP_DEVICE();
device.HASHIMEI = deviceInfo.HashImei;
ctx.MPSS_APP_DEVICE.Add(device);
ctx.SaveChanges();
}
}
Thanks
EDIT: Sample Web Request (retrieved from the comments)
Ip Address: 192.168.1.129
Url: /myproject/api/device/123456/app/appname
JSON:
{
"applicazione" : "Gestione Interventi",
"hashImei" : "123123121323123121",
"modello" : "Nexus 5",
"pushNotificatioToken" : "oifjwfijowfjfoiwjrgfoirwj42rohfoifrj",
"sistemaOperativo" : "ANDROID", "versione" : "LOLLIPOP_MR1"
}
The reason why _repository is null in your Action is because you are not initializing it in your constructor. Instead you have declared and initialized a local variable of the same name in your constructor!
public class DeviceV1Controller : ApiController
{
private readonly IDevice _repository;
public DeviceV1Controller()
{
_repository = new EFDeviceRepository();
}
// ...
}