Im a little bit confused about UserManager.Create(...).
When I use the Standard EntityFramework's IdentityUser to create and add a new User everything works fine. EntityFramework creates a database if none exists with my connectionstring Data Source=(LocalDb)\MSSQLLocalDB;Database=IdentityDemo;trusted_connection=yes; and adds a User to the Database.
ExampleProgram:
static void Main(string[] args)
{
var username = "ygg";
var password = "Password123!";
var userStore = new UserStore<IdentityUser>();
var userManager = new UserManager<IdentityUser>(userStore);
var creationResult = userManager.Create(new IdentityUser(username), password);
}
But when i try to use my own CustomUser, EntityFramework does nothing and i get a NullReferenceException at UserManager.Create(...).
Here is my Extended CustomUser Project:
static void Main(string[] args)
{
var userName = "Ygg";
var password = "Password123!";
var userStore = new CustomUserStore(new CustomUserDbContext());
var userManager = new UserManager<CustomUser, int>(userStore);
var creationResult = userManager.Create(
new CustomUser {UserName = userName}, password); //<--- Exception Here
}
CustomUser-class:
public class CustomUser : IUser<int>
{
public int Id { get; set; }
public string UserName { get; set; }
public string PasswordHash { get; set; }
}
CustomUserDbContext:
public class CustomUserDbContext : IdentityDbContext
{
public CustomUserDbContext() : base("DefaultConnection")
{
}
public DbSet<CustomUser> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var user = modelBuilder.Entity<CustomUser>();
user.ToTable("Users");
user.HasKey(x => x.Id);
user.Property(x => x.Id).IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
user.Property(x => x.UserName).IsRequired().HasMaxLength(256)
.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("UserNameIndex") { IsUnique = true }));
base.OnModelCreating(modelBuilder);
}
}
And last but not least, CustomUserStore:
public class CustomUserStore : IUserPasswordStore<CustomUser, int>
{
private readonly CustomUserDbContext _context;
public CustomUserStore(CustomUserDbContext context)
{
_context = context;
}
public void Dispose()
{
_context.Dispose();
}
public Task CreateAsync(CustomUser user)
{
_context.Users.Add(user);
return _context.SaveChangesAsync();
}
.
.
.
}
Exception:
object reference not set to an instance of an object
Stacktrace:
bei Microsoft.AspNet.Identity.UserManager2.<UpdatePassword>d__39.MoveNext()
bei System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
bei System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
bei Microsoft.AspNet.Identity.UserManager2.d__d.MoveNext()
bei System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
bei System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
bei Microsoft.AspNet.Identity.AsyncHelper.RunSync[TResult](Func1 func)
bei Microsoft.AspNet.Identity.UserManagerExtensions.Create[TUser,TKey](UserManager2 manager, TUser user, String password)
bei Identity.Program.Main(String[] args) in E:\syncplicity\z003apfp\Documents\Visual Studio 2015\Projects\Identity\Identity\Program.cs:Zeile 21.
bei System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
bei System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
I'm using EntityFramework 6.1.0 and AspNet.Identity.Core 2.2.1
Did i miss anything to configure, so AspNet.Identity and EntityFrameworks accepts my own implementations here?
Any help or thoughts where the problem lies, is appreciated.
I already tried to create the database first and then try to add a User using userManager.Create(new CustomUser {UserName = userName}, password), but this leads also to the same NullReferenceException
When you override something you should do it for the whole structure of Identity.
For example your DB Context should use something like this:
Custom Context
CustomUserDbContext : IdentityDbContext<CustomUser, CustomRole, int, CustomUserLogin, CustomUserRole, CustomUserClaim>
Custom User
User : IdentityUser<int, CustomUserLogin, CustomUserRole, CustomUserClaim>
Custom Role
CustomRole : IdentityRole<int, CustomUserRole> { }
Custom UserLogin
public class CustomUserLogin : IdentityUserLogin<int> { }
CustomUserClaim
public class CustomUserClaim : IdentityUserClaim<int> { }
Note that was an example yous should adapt according to your need.
Related
I am doing an Asp.Net Core API and I am connecting to a two databases using EF setted in appsettings.json
"ConnectionStrings": {
"DBConnection": "Server=2679; Database=A; Trusted_Connection=true; MultipleActiveResultSets=true; Integrated Security=true;Encrypt=false;",
"DBConnection2": "Server= 2684; Database=B; Trusted_Connection=true; MultipleActiveResultSets=true; Integrated Security=true;Encrypt=false;"
}
In my Program.cs I have setted this two connections
var connectionString = (builder.Configuration.GetConnectionString("DBConnection") ?? String.Empty).Trim();
var connectionString2 = (builder.Configuration.GetConnectionString("DBConnectionAnthem") ?? String.Empty).Trim();
builder.Services.ConfigureServices(connectionString);
builder.Services.ConfigureServices(connectionString2);
I call ConfigureServices with both connections and looks like this
public static class Configure
{
public static void ConfigureServices(this IServiceCollection services, string connectionString)
{
services
.AddDbContext<CobraDbContext>(options => options.UseSqlServer(connectionString));
........
services.AddScoped<IUnitOfWork, UnitOfWork>();
}
}
}
I am using EF and I have defined my DbContext like this
public class CobraDbContext : DbContext
{
public CobraDbContext(DbContextOptions<CobraDbContext> options)
: base(options)
{
}
public DbSet<SearchResultModel> ParticipantSearch { get; set; } = null!;
....
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
}
}
}
From My Controller Method I call the Service.cs witch use UnitOfwork
public class ParticipantService : IParticipantService
{
private readonly ILogger<ParticipantService> _logger;
private readonly IUnitOfWork _iUnitOfwork;
public ParticipantService(ILogger<ParticipantService> logger, IUnitOfWork iUnitOfwork)
{
_logger = logger;
_iUnitOfwork = iUnitOfwork;
}
public async Task<HttpResponseMessage> Search(string participantId)
{
try
{
List<SearchResultModel>? search = await _iUnitOfwork.Participant.AAA(participantId);
return Request.CreateResponse(HttpStatusCode.OK, search);
}
catch (Exception ex)
{
}
}
From My Service I call the Repository that have a generic repository
public class ParticipantRepository : GenericRepository<SearchResultModel>, IParticipantRepository
{
private readonly CobraDbContext _db;
public ParticipantRepository(CobraDbContext db) : base(db)
{
_db = db;
}
public async Task<List<ParticipantPlanModel>?> AAA(string participantId)
{
Query participantGetByID = new();
Dictionary<string, string> dictionary = new Dictionary<string, string>();
participantGetByID.SelectFrom = " exec sp";
List<ParticipantPlanModel>? _return = await ExecuteGeneric(participantGetByID);
return _return;
}
}
I have my generic repo like this
public class GenericRepository<T> : IGenericRepository<T> where T : class
{
protected readonly CobraDbContext Context;
internal DbSet<T> dbSet;
public GenericRepository(CobraDbContext context)
{
Context = context;
dbSet = context.Set<T>();
}
public async Task<List<T>?> ExecuteGeneric(Query query)
{
// var defaultVal = default(T);
var cParameters = new SqlParameter[query.Parameters?.Count ?? 0];
if (query.Parameters != null)
{
int i = 0;
foreach (KeyValuePair<string, string> _param in query.Parameters)
{
cParameters[i] = new SqlParameter() { ParameterName = _param.Key, Value = _param.Value };
i++;
}
}
return await Context.Set<T>().FromSqlRaw(query.SelectFrom + query.Where + query.OrderBy, cParameters).ToListAsync();
}
Depending on the parameter I have to call a database or a the another. I know I can do this duplicating almost all the code... Having to DbContext and two generic Repo..
Is there a way to simplify it and not replicate most of the code?
Thanks
Sorry this is a bit new to me so I don't quite 'get it'.
I already have a logging provider
public void ConfigureServices(IServiceCollection services)
{
services.AddLogging(loggingBuilder =>
{
var loggingSection = Configuration.GetSection("Logging");
loggingBuilder.AddFile(loggingSection);
loggingBuilder.AddConsole();
loggingBuilder.AddDebug();
I am using the package NReco.Logging.File to define AddFile etc.
I want to make it so that exceptions are emailed to me too. So I followed https://learn.microsoft.com/en-us/dotnet/core/extensions/custom-logging-provider to create a custom logger.
public sealed class EmailLoggerConfiguration
{
public int EventId { get; set; }
public string EmailToSendTo { get; set; }
public IEmailSender EmailSender { get; set; }
}
internal class EmailLoggingProvider : ILoggerProvider
{
private readonly IDisposable? _onChangeToken;
private EmailLoggerConfiguration _currentConfig;
private readonly ConcurrentDictionary<string, EmailLogger> _loggers =
new(StringComparer.OrdinalIgnoreCase);
private readonly IEmailSender emailSender;
public EmailLoggingProvider(
IOptionsMonitor<EmailLoggerConfiguration> config)
{
_currentConfig = config.CurrentValue;
_onChangeToken = config.OnChange(updatedConfig => _currentConfig = updatedConfig);
}
public ILogger CreateLogger(string categoryName) =>
_loggers.GetOrAdd(categoryName, name => new EmailLogger(name, GetCurrentConfig ));
private EmailLoggerConfiguration GetCurrentConfig() => _currentConfig;
public void Dispose()
{
_loggers.Clear();
_onChangeToken?.Dispose();
}
}
internal class EmailLogger : ILogger
{
private readonly string categoryName;
private Func<EmailLoggerConfiguration> getCurrentConfig;
IEmailSender emailSender;
public EmailLogger(string categoryName, Func<EmailLoggerConfiguration> getCurrentConfig)
{
this.getCurrentConfig = getCurrentConfig;
this.categoryName = categoryName;
}
public IDisposable? BeginScope<TState>(TState state) where TState : notnull => default!;
public bool IsEnabled(LogLevel logLevel) => !String.IsNullOrEmpty(getCurrentConfig().EmailToSendTo);
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
var emailTo = getCurrentConfig().EmailToSendTo;
//var emailServer = getCurrentConfig().EmailSender;
if (!String.IsNullOrEmpty(emailTo) && exception != null)
{
emailSender.SendEmailAsync(emailTo, "Admin exception", exception.ToString());
}
}
}
public static class EmailLoggingExtensions
{
public static ILoggingBuilder AddEmailLogger(
this ILoggingBuilder builder)
{
builder.AddConfiguration();
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, EmailLoggingProvider>());
LoggerProviderOptions.RegisterProviderOptions<EmailLoggerConfiguration, EmailLoggingProvider>(builder.Services);
return builder;
}
public static ILoggingBuilder AddEmailLogger(
this ILoggingBuilder builder,
Action<EmailLoggerConfiguration> configure)
{
builder.AddEmailLogger();
builder.Services.Configure(configure);
return builder;
}
}
You can see that EmailLogger.Log requires emailSender which should be an IEmailSender but I cannot figure out how to get it there using DI.
I realise that you can chain dependencies in DI but ???? I don't see how in this context.
I tried this
loggingBuilder.AddEmailLogger(c =>
{
c.EmailToSendTo = Configuration["Logging:Email:EmailToSendTo"];
c.EmailSender = new AuthMessageSender(????, Configuration);
});
but that didn't help and wouldn't even be right anyway.
In fact, by default, EmailSender is the implementation method of IEmailSender, which is used to call the SendEmailAsync() method. You don't need to go and set c.EmailSender = xxx.
You can consider the following dependency injection approach:
public interface IEmailSender
{
Task SendEmailAsync(string email, string subject, string message);
}
public class EmailSender : IEmailSender
{
//...
private readonly ILogger<EmailSender> logger;
public EmailSender(ILogger<EmailSender> logger) {
//...
this.logger = logger;
}
public Task SendEmailAsync(string email, string subject, string message) {
//...
}
}
At this point, IEmailSender will exist as a custom interface instead of inheriting from Microsoft.AspNetCore.Identity.UI.Services.
And you need to register it as a service:
services.AddTransient<IEmailSender, EmailSender>();
Helpful links:
Add ILogger to send email service
Should I use IEmailSender?
Using IEmailSender from Configure() in my Startup.cs file
Hope this will help you better understand IEmailSender and dependency injection.
I'm trying to implement multi-database structure with automatic migrations.
databases uncountable and i can't set the a fixed connection strings.
i tried many ways to handle it, some ways worked but could not handle automatic migrations.
I have two different DbContexts and different connection strings
the question is:
Is this a good way to handle it or there is a better one ?
public class CategoriesController : Controller
{
private readonly UserDbContext _context;
public CategoriesController(UserDbContext context, ApplicationDbContext _Maincontext)
{
var conn = _Maincontext.Users.FirstOrDefault().DbId;
context.Database.SetConnectionString($"Data Source=.\\SQLEXPRESS;Initial Catalog={conn};Integrated Security=False; uid=sa;password=123;");
context.Database.Migrate();
_context = context;
}
// GET: Categories
public async Task<IActionResult> Index()
{
return Ok(await _context.Categories.ToListAsync());
}
}
I've used the Users Claims to handle this problem
Startup
public void ConfigureServices(IServiceCollection services)
{
// First Context which has a static connection string
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("mainDb")));
// To inject HttpContext for each request
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
// Second Context which has a dynamic connection strings
services.AddDbContext<UserDbContext>();
).AddEntityFrameworkStores<ApplicationDbContext>();
services.AddControllersWithViews();
}
UserDbContext class
public class UserDbContext : DbContext
{
private readonly HttpContext _httpContext;
public UserDbContext(DbContextOptions<UserDbContext> options, IHttpContextAccessor httpContextAccessor = null)
: base(options)
{
_httpContext = httpContextAccessor?.HttpContext;
}
//..
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
//First get user claims
var claims = _httpContext?.User.Claims.ToList();
//Filter specific claim
string dbName = claims?.FirstOrDefault(x => x.Type.Equals("db", StringComparison.OrdinalIgnoreCase))?.Value;
if (dbName == null) dbName = "TempDebugDb";
optionsBuilder.UseSqlServer(GetConnectionString(dbName));
}
}
private static string GetConnectionString(string dbName)
{
return $"Data Source=.\\SQLEXPRESS;Initial Catalog={dbName};Integrated Security=False; uid=sa;password=*****;";
}
public DbSet<Category> Categories { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
I have implemented Unit Of Work and facing following the error, earlier the project implemented well when I just implemented Repository. This is the error I'm getting in my Browser (Google Chrome Version 90.0.4430.212 (Official Build) (64-bit)):
Server Error in '/' Application.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.MissingMethodException: No parameterless constructor defined for this object.
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
Stack Trace:
[MissingMethodException: No parameterless constructor defined for this object.]
System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) +0
System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) +122
System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) +239
System.Activator.CreateInstance(Type type, Boolean nonPublic) +85
System.Activator.CreateInstance(Type type) +12
System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +55
[InvalidOperationException: An error occurred when trying to create a controller of type 'OfficeWork.Controllers.PopulationsController'. Make sure that the controller has a parameterless public constructor.]
System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +178
System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType) +80
System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName) +102
System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory) +188
System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +50
System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +48
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +16
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +105
System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step) +50
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +163
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.8.4330.0
"IUnitOfWork" interface:
using System.Threading.Tasks;
namespace OfficeWork.DAL
{
interface IUnitOfWork
{
IStudentRepository StudentRepository { get; }
IStudentRepositoryRole StudentRepositoryRole { get; }
Task<bool> SaveAsync();
}
}
UnitOfWork:
using System.Threading.Tasks;
namespace OfficeWork.DAL
{
public class UnitOfWork : IUnitOfWork
{
private readonly PopulationDBContext dc;
public UnitOfWork(PopulationDBContext dc)
{
this.dc = dc;
}
public IStudentRepository StudentRepository =>
new StudentRepository(dc);
public IStudentRepositoryRole StudentRepositoryRole =>
new StudentRepositoryRole(dc);
public async Task<bool> SaveAsync()
{
return await dc.SaveChangesAsync() > 0;
}
}
}
Controller:
using OfficeWork.DAL;
using OfficeWork.ED;
using OfficeWork.Models;
using System.Collections.Generic;
using System.Web.Mvc;
namespace OfficeWork.Controllers
{
public class PopulationsController : Controller
{
private readonly IUnitOfWork uow;
Password password_hiding = new Password();
PopulationsController(IUnitOfWork uow)
{
this.uow = uow;
}
//Direct to homepage after logging in
public ActionResult HomePage(int id)
{
Population population = uow.StudentRepository.GetStudentByID(id);
return View(population);
}
//Controller used to update existing information
[HttpPost]
public ActionResult UpdatePopulation(Population std, int id)
{
{
Population updatestd = uow.StudentRepository.GetStudentByID(id);
if (!string.IsNullOrWhiteSpace(std.Email)) { updatestd.Email = std.Email; }
if (!string.IsNullOrWhiteSpace(std.FirstName)) { updatestd.FirstName = std.FirstName; }
if (!string.IsNullOrWhiteSpace(std.LastName)) { updatestd.LastName = std.LastName; }
{ updatestd.MobileNumber = std.MobileNumber; }
{ updatestd.DateOfBirth = std.DateOfBirth; }
{ updatestd.Password =password_hiding.encrypt(std.Password); }
uow.StudentRepository.UpdateStudent(updatestd);
uow.SaveAsync();
}
return Json(true, JsonRequestBehavior.AllowGet);
}
//Controller used to direct to the Edit page
public ActionResult Edit(int val)
{
Population p = uow.StudentRepository.GetStudentByID(val);
p.Password = password_hiding.Decrypt(p.Password);
return View(p);
}
//Main page is the page consisting of user details
public ActionResult UserDetails(int val)
{
Population std = uow.StudentRepository.GetStudentByID(val);
return View(std);
}
public ActionResult SignIn(int? id)
{
return View();
}
//This post Sign in controller helps in authenticating user and redirecting it the user details page
[HttpPost]
public ActionResult SignIn(string email, string password)
{
var new_pas =password_hiding.encrypt(password);
Population dbs = uow.StudentRepository.GetStudentByEmailPass(email, new_pas);
int id = dbs.ID;
Role ro = uow.StudentRepositoryRole.GetStudentByID(id);
if(ro!=null)
{
return RedirectToAction("Admin");
}
if (dbs != null)
{
return RedirectToAction("HomePage/"+id);
}
else
{
return View();
}
}
public ActionResult SignUp()
{
return View();
}
// This POST controller is used to sign up. It takes values(Email,FirstName,LastName,MobileNumber,DateOfBirth,Password) from the page and add it to the database.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SignUp([Bind(Include = "Email,FirstName,LastName,MobileNumber,DateOfBirth,Password")] Population population)
{
if (ModelState.IsValid)
{
population.Password =password_hiding.encrypt(population.Password);
uow.StudentRepository.InsertStudent(population);
uow.SaveAsync();
return RedirectToAction("SignIn");
}
return View(population);
}
//If Username: anirudhrawat1#gmail.com and Password:Solution or Username: arnav#gmail.com and Password: Hello is entered to SIGN IN page then it will direct the user to List of entries.
public ActionResult Admin()
{
IEnumerable<Population> students = uow.StudentRepository.GetStudents();
return View(students);
}
}
}
"StudentRepository" repository file of "Population":
using OfficeWork.Models;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
namespace OfficeWork.DAL
{
public class StudentRepository : IStudentRepository, IDisposable
{
private PopulationDBContext context;
public StudentRepository(PopulationDBContext context)
{
this.context = context;
}
public IEnumerable<Population> GetStudents()
{
return context.Populations.ToList();
}
public Population GetStudentByID(int id)
{
return context.Populations.Find(id);
}
public Population GetStudentByEmailPass(string email, string password)
{
return context.Populations.FirstOrDefault(e => e.Email == email && e.Password == password);
}
public void InsertStudent(Population student)
{
context.Populations.Add(student);
}
public void DeleteStudent(int studentID)
{
Population student = context.Populations.Find(studentID);
context.Populations.Remove(student);
}
public void UpdateStudent(Population student)
{
context.Entry(student).State = EntityState.Modified;
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
"IStudentRepository" interface file:
using OfficeWork.Models;
using System;
using System.Collections.Generic;
namespace OfficeWork.DAL
{
public interface IStudentRepository : IDisposable
{
IEnumerable<Population> GetStudents();
Population GetStudentByID(int studentId);
void InsertStudent(Population student);
Population GetStudentByEmailPass(string email, string password);
void DeleteStudent(int studentID);
void UpdateStudent(Population student);
}
}
"StudentRepositoryRole" repository file of "Role":
using OfficeWork.Models;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
namespace OfficeWork.DAL
{
public class StudentRepositoryRole : IStudentRepositoryRole, IDisposable
{
private PopulationDBContext context;
public StudentRepositoryRole(PopulationDBContext context)
{
this.context = context;
}
public IEnumerable<Role> GetStudents()
{
return context.Roles.ToList();
}
public Role GetStudentByID(int id)
{
return context.Roles.Find(id);
}
public void InsertStudent(Role student)
{
context.Roles.Add(student);
}
public void DeleteStudent(int studentID)
{
Role student = context.Roles.Find(studentID);
context.Roles.Remove(student);
}
public void UpdateStudent(Role student)
{
context.Entry(student).State = EntityState.Modified;
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
"IstudentRepositoryRole" interface file:
using OfficeWork.Models;
using System;
using System.Collections.Generic;
namespace OfficeWork.DAL
{
public interface IStudentRepositoryRole : IDisposable
{
IEnumerable<Role> GetStudents();
Role GetStudentByID(int studentId);
void InsertStudent(Role student);
void DeleteStudent(int studentID);
void UpdateStudent(Role student);
}
}
PopulationDBContext:
using OfficeWork.Models;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;
namespace OfficeWork.DAL
{
public class PopulationDBContext : DbContext
{
public DbSet<Population> Populations { get; set; }
public DbSet<Role> Roles { get; set; }
}
}
The main issue was "dependency injection".
private readonly IUnitOfWork uow;
PopulationsController(IUnitOfWork uow)
{
this.uow = uow;
}
I installed Unity.Mvc5 from Nuget Packages. I has in-built configuration to make dependency injections.
After adding Unity.Mvc5. It created UnityConfig.cs file in App_start automatically.
1)Add "container.RegisterType<Interface, Repository>();" in UnityConfig.cs
2)Add "UnityConfig.RegisterComponents();" in Global.asax.cs.
I have some ASP.NET Core MVC middleware to catch unhandled exceptions that I would like to return a response from.
While it is easy to just httpContext.Response.WriteAsync to write a string and e.g. use JsonSerializer to serialise an object to a string, I would like to use the standard serialisation settings and content negotiation so that if I change my default output formatting to XML or a text/xml accept header is sent when I have multiple output formatters configured then XML is returned, as it does if I return an ObjectResult from a controller.
Does anyone know how this can be achieved in middleware?
Here is my code so far which only writes JSON:
public class UnhandledExceptionMiddleware
{
private readonly RequestDelegate _next;
private readonly IOutputFormatter _outputFormatter;
private readonly IHttpResponseStreamWriterFactory _streamWriterFactory;
public UnhandledExceptionMiddleware(RequestDelegate next, JsonOutputFormatter outputFormatter, IHttpResponseStreamWriterFactory streamWriterFactory)
{
_next = next;
_outputFormatter = outputFormatter;
_streamWriterFactory = streamWriterFactory;
}
public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}
private async Task HandleExceptionAsync(HttpContext context, Exception exception)
{
var error = new ErrorResultModel("Internal Server Error", exception.Message, exception.StackTrace);
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
await _outputFormatter.WriteAsync(new OutputFormatterWriteContext(context, _streamWriterFactory.CreateWriter, typeof(ErrorResultModel), error));
}
}
where ErrorResultModel is defined as:
public class ErrorResultModel
{
public string ResultMessage { get; };
public string ExceptionMessage { get; };
public string ExceptionStackTrace { get; };
public ErrorResultModel(string resultMessage, string exceptionMessage, string exceptionStackTrace)
{
ResultMessage = resultMessage;
ExceptionMessage = exceptionMessage;
ExceptionStackTrace = exceptionStackTrace;
}
}
This is not possible in ASP.NET Core 2.0 MVC.
This will be possible in 2.1:
public static class HttpContextExtensions
{
private static readonly RouteData EmptyRouteData = new RouteData();
private static readonly ActionDescriptor EmptyActionDescriptor = new ActionDescriptor();
public static Task WriteResultAsync<TResult>(this HttpContext context, TResult result)
where TResult : IActionResult
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var executor = context.RequestServices.GetService<IActionResultExecutor<TResult>>();
if (executor == null)
{
throw new InvalidOperationException($"No result executor for '{typeof(TResult).FullName}' has been registered.");
}
var routeData = context.GetRouteData() ?? EmptyRouteData;
var actionContext = new ActionContext(context, routeData, EmptyActionDescriptor);
return executor.ExecuteAsync(actionContext, result);
}
}
public class Program : StartupBase
{
public static Task Main(string[] args)
{
return BuildWebHost(args).RunAsync();
}
public static IWebHost BuildWebHost(string[] args)
{
return new WebHostBuilder().UseStartup<Program>().UseKestrel().Build();
}
public override void ConfigureServices(IServiceCollection services)
{
services.AddMvcCore().AddJsonFormatters();
}
public override void Configure(IApplicationBuilder app)
{
app.Use((ctx, next) =>
{
var model = new Person("Krisian", "Hellang");
var result = new ObjectResult(model);
return ctx.WriteResultAsync(result);
});
}
}
public class Person
{
public Person(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
}
public string FirstName { get; }
public string LastName { get; }
}