DbContextOptions parameters ASP.net core - c#

I am getting ArgumentNullException: Value cannot be null. Parameter name: options
I think it's because of my default constructor that I get null but If I comment out the constructor then the new instance of a class needs parameters which I don't know what to give in. HELP PLEASE
public class OvertimeRequestBusiness
{
public static OvertimeRequestBusiness Instance { get; } = new OvertimeRequestBusiness();
private readonly DbContextOptions<DatabaseContext> _contextOptions;
//default ctor
public OvertimeRequestBusiness() : base() { }
public OvertimeRequestBusiness(DbContextOptions<DatabaseContext> contextOptions)
{
_contextOptions = contextOptions;
}
public async Task<List<User>> GetAllUsersAsync()
{
using (var ctx = new DatabaseContext(_contextOptions))
{
var query = ctx.Users;
var res = await query.ToListAsync();
return res;
}
}
}
In my controller
[Route("users")]
[HttpGet]
public async Task<List<User>> GetAllUsers()
{
return await OvertimeRequestBusiness.Instance.GetAllUsersAsync();
}

Here is how you can create DbContextOptions:
var optionsBuilder = new DbContextOptionsBuilder<DatabaseContext>();
optionsBuilder.UseSqlServer("connection_string_here");
then DbContextOptions<DatabaseContext> will be available as optionsBuilder.Options. You can pass it to OvertimeRequestBusiness.ctor:
new OvertimeRequestBusiness(optionsBuilder.Options);

Related

Call a class constructor with parameter inside the parent class

I have this class as you can see :
public class mybaseclass
{
public string token = "";
private readonly HttpContextAccessor iHTTP;
public mybaseclass([FromServices]HttpContextAccessor IHTTP)
{
//this.httpContext = httpContext;
iHTTP = IHTTP;
}
public mybaseclass()
{
}
protected Task<HttpRequestMessage> CreateHttpRequestMessageAsync(CancellationToken cancellationToken)
{
// var t = null;
try
{
// iHTTP.HttpContext.Request.Cookies[key]
var t = iHTTP.HttpContext.Request.Cookies["Authorization"];
if (t == null)
{
token = t;
}
}
catch(Exception aaa)
{
}
var msg = new HttpRequestMessage();
// SET THE BEARER AUTH TOKEN
msg.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
return Task.FromResult(msg);
}
}
And this class is called in this class :
public partial class Default1Client : mybaseclass, IDefault1Client
{
private string _baseUrl = "";
private System.Lazy<Newtonsoft.Json.JsonSerializerSettings> _settings;
public Default1Client(string baseUrl)
{
BaseUrl = baseUrl;
_settings = new System.Lazy<Newtonsoft.Json.JsonSerializerSettings>(CreateSerializerSettings);
}
// other part of code
}
My problem is when I call Default1Client,the class calls the mybaseclass constructor that doesn't have any parameters ,but I need the constructor with httpcontextaccessorto be called
Modify your constructor to pass it through:
public Default1Client(string baseUrl, HttpContextAccessor contextAccessor) : base(contextAccessor)
{
//etc....
And populate it when you register:
services.AddScoped<IDefault1Client>(provider => { return new Default1Client
(
"localhost:44381",
provider.GetService(typeof(HttpContextAccessor)) as HttpContextAccesor
)});
In this case you want to specify the parameters, we can inject them using a function that will get the httpContextAccessor from your baseurl:
// you can use a function call to get the accessor
public Default1Client(string baseUrl) : mybaseclass(getHttpContextAccessor(baseUrl))
If you pass it the parameters that will correspond to httpcontextaccessor the constructor which takes parameters will be called.

Cannot implicitly convert type C# .Net Core Issue

What I'm trying to do is make an api service using .NET Core where I am making an array from a database .... I'm getting a 'Cannot implicitly convert type 'System.Action[] to SynCore.DbrAction[]'.
Am I going in the right direction? I'm trying to make a api service that my Angular client can consume.
Action Controller
public class ActionsController : ControllerBase
{
private IActionService _actionService;
public ActionsController(IActionService actionService)
{
_actionService = actionService;
}
//GET: api/Actions
[HttpGet]
public IActionResult GetActions(string userId, string sessionId)
{
// TODO: Figure out when recurseOnMenus is true, pass it accordingly instead of forcing false.
DbrAction[] dbrActions = _actionService.GetActions(userId, sessionId);
return Ok(dbrActions);
}
Action Service
public interface IActionService
{
Action[] GetActions(string userId, string sessionId);
}
public class ActionService : IActionService
{
private DataContext _context;
public ActionService(DataContext context)
{
_context = context;
}
public DbrAction[] GetActions(string sessionId)
{
UserStateHelper ush = new UserStateHelper();
UserState us = ush.CreateUserState(sessionId);
XioTable xt = new XioTable(us, T.User);
DbrUser user = (DbrUser)xt.LoadSingleRow(us.UserTag, C.User_DefaultActionTag);
Actions[] actions = {};
List<DbrAction> dbrActions = new List<DbrAction>();
xt = new XioTable(us, T.Action);
xt.SelectCols(C.Action_Description, C.Action_ActionName, C.Action_FolderTag, C.Action_ActionType, C.Action_PrimaryTable);
xt.LoadData();
foreach (DbrAction action in xt.GetAllRows(C.Action_FolderTag))
{
if (!DbrAction.IsTableDeprecated(action.PrimaryTable))
{
if (action.ActionType == ActionType.View || action.ActionType == ActionType.Dashboard)
dbrActions.Add(action);
}
}
us.Completed(LogEntryType.GetStartupProfileData, null);
return dbrActions.ToArray();
}
public Action[] GetActions(string userId, string sessionId)
{
throw new NotImplementedException();
}

How should I get the Request in ApiController constructor?

Task
I have a DataMapper class that I use to map data into custom representations for my web api's mobile client.
public class DataMapper
{
public static string Role { get; set; }
public static RoleReturnModel Create(IdentityRole appRole)
{
return new RoleReturnModel
{
Id = appRole.Id,
Name = appRole.Name
};
}
public static CountryReturnModel Create(Country country)
{
return new CountryReturnModel
{
Id = country.Id,
Name = country.Name,
CityList = country.Cities.Select(city => DataMapper.Create(city))
};
}
public static CityReturnModel Create(City city)
{
return new CityReturnModel
{
Id = city.Id,
Name = city.Name,
};
}
}
The first property as you can see is called Role. I need to populate that with whichever role is accessing my web method. This is so because at times I need conditional mapping to return role specific data representations to the client.
Problem
I thought the best place to do DataMapper.Role = CurrentRole would be in the constructor of my ApiController
public class BaseApiController : ApiController
{
private ModelFactory _modelFactory;
private ApplicationUserManager _AppUserManager = null;
private ApplicationRoleManager _AppRoleManager = null;
protected BaseApiController()
{
//Request is null here
DataMapper.Role = Request.GetOwinContext().GetUserManager<ApplicationRoleManager>().FindById(User.Identity.GetUserId()).Name;
}
This however doesn't work . The Request object is null in the constructor. It only gets filled in my actual web method
public class UsersController : BaseApiController
{
IUserRepository UserRepository;
public UsersController() // will use ninject for constructor injection
{
UserRepository = new UserRepository();
}
[Route("profile")]
public IHttpActionResult GetUser()
{
//Request is available here
}
I am a webapi noobie. Need pointers to this problem.
The request is not available as yet in the constructor. You can only access it in an action/method after the controller has already been initialized.
public class BaseApiController : ApiController {
private ModelFactory _modelFactory;
private ApplicationUserManager _AppUserManager = null;
private ApplicationRoleManager _AppRoleManager = null;
protected string GetRole() {
return Request.GetOwinContext()
.GetUserManager<ApplicationRoleManager>()
.FindById(User.Identity.GetUserId()).Name;
}
And accessed
public class UsersController : BaseApiController {
IUserRepository UserRepository;
public UsersController() // will use ninject for constructor injection
{
UserRepository = new UserRepository();
}
[Route("profile")]
public IHttpActionResult GetUser()
{
//Request is available here
var role = GetRole();
}
Or consider extracting that out into an extension method so that it can be reused
var role = this.GetUserRole();
Where
public static string GetUserRole(this ApiController controller) {
var request = controller.Request;
var user = controller.User
return request.GetOwinContext()
.GetUserManager<ApplicationRoleManager>()
.FindById(user.Identity.GetUserId()).Name;
}

Getting error with aspnet core 2.1 action filter due to missing suitable constructor

I have made a claims filter
public class ClaimRequirementAttribute : TypeFilterAttribute
{
public ClaimRequirementAttribute(string claimType, ClaimRoles claimValue) : base(typeof(ClaimRequirementFilter))
{
Arguments = new object[] {new Claim(claimType, claimValue.ToString()) };
}
}
public class ClaimRequirementFilter : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
var headers = context.HttpContext.Request.Headers;
var tokenSuccess = headers.TryGetValue("Token", out var token);
var emailSuccess = headers.TryGetValue("Email", out var email);
var deviceNameSuccess = headers.TryGetValue("DeviceName", out var deviceName);
if (tokenSuccess && emailSuccess && deviceNameSuccess)
{
var accountLogic = context.HttpContext.RequestServices.GetService<IAccountLogic>();
var hasClaim = accountLogic.ValidateLogin(email, token, deviceName).Result.Success;
if (!hasClaim)
{
context.HttpContext.ForbidAsync();
}
}
else
{
context.HttpContext.ForbidAsync();
}
}
}
I have registered the filter in my startup
public void ConfigureServices(IServiceCollection services)
{
services.Configure<ConnectionStringsSettings>(Configuration.GetSection("ConnectionStrings"));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddScoped<ClaimRequirementFilter>();
But I get this error when I navigate to an action that uses the filter
[HttpPost]
[ClaimRequirement("Permission", ClaimRoles.Admin)]
public async Task ResetLeaderboard()
InvalidOperationException: A suitable constructor for type 'Foosball.Logic.ClaimRequirementFilter' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor
github: https://github.com/Mech0z/Foosball/tree/core2.1/Foosball
As your code has
Arguments = new object[] {new Claim(claimType, claimValue.ToString()) };
you need to add the following constructor:
public ClaimRequirementFilter(Claim claim)
{
}
That is because the internal constructor resolving logic uses TypeFilterAttribute.Argument property to decide what constructor to use for instantiation.

Controller API Testing with xUnit/Moq - Controller is null

I'm new to unit testing, so my problem is probably with my code and not the Moq framework, but here goes.
I'm using .Net Core with xUnit and the Moq framework, and I'm more or less following instructions from their documentation. I'm trying to test route api/user to get all users, and the issue was on asserting that the response was an ObjectResult containing <IEnumerable<User>>. No matter what I tried, result.Value was always null. The first assertion passes fine.
I set up a console project to debug this, and found something interesting. that value of the controller in the test method in Visual Studio is null. In VS Code, the value in the debugger shows Unknown Error: 0x00000....
Below is the test:
public class UserControllerTests {
[Fact]
public void GetAll_ReturnsObjectResult_WithAListOfUsers() {
// Arrange
var mockService = new Mock<IUserService>();
var mockRequest = new Mock<IServiceRequest>();
mockService.Setup(svc => svc.GetUsers(mockRequest.Object))
.Returns(new ServiceRequest(new List<User> { new User() }));
var controller = new UserController(mockService.Object);
// Act
var result = controller.GetAll();
// Assert
Assert.IsType<ObjectResult>(result);
Assert.IsAssignableFrom<IEnumerable<User>>(((ObjectResult)result).Value);
}
}
And here is the controller:
public class UserController : Controller {
private IUserService service;
public UserController(IUserService service) {
this.service = service;
}
[HttpGet]
public IActionResult GetAll() {
var req = new ServiceRequest();
service.GetUsers(req);
if(req.Errors != null) return new BadRequestObjectResult(req.Errors);
return new ObjectResult(req.EntityCollection);
}
}
And the Service Layer:
public interface IUserService {
IServiceRequest GetUsers(IServiceRequest req);
}
public class UserService : IUserService {
private IUserRepository repo;
public IServiceRequest GetUsers(IServiceRequest req) {
IEnumerable<User> users = null;
try {
users = repo.GetAll();
}
catch(MySqlException ex) {
req.AddError(new Error { Code = (int)ex.Number, Message = ex.Message });
}
finally {
req.EntityCollection = users;
}
return req;
}
}
public interface IServiceRequest {
IEnumerable<Object> EntityCollection { get; set; }
List<Error> Errors { get; }
void AddError(Error error);
}
public class ServiceRequest : IServiceRequest {
public IEnumerable<Object> EntityCollection { get; set; }
public virtual List<Error> Errors { get; private set; }
public ServiceRequest () { }
public void AddError(Error error) {
if(this.Errors == null) this.Errors = new List<Error>();
this.Errors.Add(error);
}
}
Like I said, it's probably something I'm doing wrong, I'm thinking in the mockService.Setup() but I'm not sure where. Help please?
From the use of service.GetUsers(req) it looks like service is suppose to populate the service request but in your setup you have it returning a service request. A result which is also not used according to your code.
You need a Callback to populate whatever parameter is given to the service in order to mock/replicate when it is invoked. Since the parameter is being created inside of the method you will use Moq's It.IsAny<> to allow the mock to accept any parameter that is passed.
var mockService = new Mock<IUserService>();
mockService.Setup(svc => svc.GetUsers(It.IsAny<IServiceRequest>()))
.Callback((IServiceRequest arg) => {
arg.EntityCollection = new List<User> { new User() };
});
This should allow the method under test to flow through it's invocation and allow you to assert the outcome.

Categories

Resources