Error When Seeding Users - MVC5 EF6 Identity 2.0 - asp.net-mvc

We're working on our seed method for our database, and have tried a variety of different things to make it work, but it keeps erroring out.
Our seed method is
protected override void Seed(WebApplication1.Models.ApplicationDbContext context)
{
if (!context.Roles.Any(r => r.Name == "Admin"))
{
var store = new RoleStore<IdentityRole>(context);
var manager = new RoleManager<IdentityRole>(store);
var role = new IdentityRole {Name = "Admin"};
manager.Create(role);
}
if (!context.Users.Any(u => u.UserName == "Admin"))
{
var store = new UserStore<ApplicationUser>(context);
var manager = new UserManager<ApplicationUser>(store);
var user = new ApplicationUser {UserName = "Admin"};
manager.Create(user, "ChangeItAsap!");
manager.AddToRole(user.Id, "Admin");
}
}
The error is
The type 'WebApplication1.Models.ApplicationUser' cannot be used as type parameter 'TUser' in the generic type or method 'Microsoft.AspNet.Identity.EntityFramework.UserStore<TUser>'. There is no implicit reference conversion from 'WebApplication1.Models.ApplicationUser' to 'Microsoft.AspNet.Identity.EntityFramework.IdentityUser'.
With the following line being the cause
var store = new UserStore<ApplicationUser>(context);
I'm not entirely sure what could be causing this, as I've never ran into this issue in the past. any help would be appreciated.
EDIT
Here is the definition
public class ApplicationUserLogin : IdentityUserLogin<string> { }
public class ApplicationUserClaim : IdentityUserClaim<string> { }
public class ApplicationUserRole : IdentityUserRole<string> { }
// Must be expressed in terms of our custom Role and other types:
public class ApplicationUser
: IdentityUser<string, ApplicationUserLogin,
ApplicationUserRole, ApplicationUserClaim>
{
public ApplicationUser()
{
this.Id = Guid.NewGuid().ToString();
// Add any custom User properties/code here
}
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(ApplicationUserManager manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
public class ApplicationRole : IdentityRole<string, ApplicationUserRole>
{
public ApplicationRole()
{
this.Id = Guid.NewGuid().ToString();
}
public ApplicationRole(string name)
: this()
{
this.Name = name;
}
// Add any custom Role properties/code here
}
public class ApplicationDbContext
: IdentityDbContext<ApplicationUser, ApplicationRole,
string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
// Most likely won't need to customize these either, but they were needed because we implemented
// custom versions of all the other types:
public class ApplicationUserStore
: UserStore<ApplicationUser, ApplicationRole, string,
ApplicationUserLogin, ApplicationUserRole,
ApplicationUserClaim>, IUserStore<ApplicationUser, string>,
IDisposable
{
public ApplicationUserStore()
: this(new IdentityDbContext())
{
base.DisposeContext = true;
}
public ApplicationUserStore(DbContext context)
: base(context)
{
}
}
public class ApplicationRoleStore
: RoleStore<ApplicationRole, string, ApplicationUserRole>,
IQueryableRoleStore<ApplicationRole, string>,
IRoleStore<ApplicationRole, string>, IDisposable
{
public ApplicationRoleStore()
: base(new IdentityDbContext())
{
base.DisposeContext = true;
}
public ApplicationRoleStore(DbContext context)
: base(context)
{
}
}

Related

CustomModelBinder on properties of a Dto class

I have a DtoClass which has properties of a specific class, I don't want to have a CustomModelBinder for the DtoClass but for the class of its properties; I am using asp.net core 3.1.
My ModelBinder Class is:
public class SessionIdModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
Guard.Against.Null(bindingContext, nameof(bindingContext));
var modelName = bindingContext.ModelName;
var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
if (valueProviderResult == ValueProviderResult.None)
return Task.CompletedTask;
var sessionId = SessionId.Parse(valueProviderResult.FirstValue);
if (sessionId.IsFailure)
{
bindingContext.ModelState.AddModelError(modelName, sessionId.Errors.First().Message);
bindingContext.Result = ModelBindingResult.Failed();
return Task.CompletedTask;
}
bindingContext.Result = ModelBindingResult.Success(sessionId.Data);
return Task.CompletedTask;
}
}
The Dto class is like:
public class MergeSessionsDto
{
[ModelBinder(BinderType = typeof(SessionIdModelBinder), Name = nameof(OldSession))]
public SessionId OldSession { get; set; }
[ModelBinder(BinderType = typeof(SessionIdModelBinder), Name = nameof(NewSession))]
// [BindProperty(BinderType = typeof(SessionIdModelBinder), Name = nameof(NewSession))]
public SessionId NewSession { get; set; }
}
The action in my controller is:
public async Task<IActionResult> MergeSessions([FromBody] MergeSessionsDto dto)
{
var result = DoTheMerge(dto.OldSession, dto.NewSession);
return result;
}
in the startup class I also registered the ModelBinderProvider :
services.AddControllers(options=> options.ModelBinderProviders.Insert(0, new MyCustomModelBinderProvider()))
which is like:
public sealed class MyCustomModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
Guard.Against.Null(context, nameof(context));
if (context.Metadata.ModelType == typeof(SessionId))
return new BinderTypeModelBinder(typeof(SessionIdModelBinder));
return null;
}
}
No matter which approach I am using, either [ModelBinder], [BindProperty] attributes, or global registration, SessionModelBinder is not called, and I am getting this error:
Exception: Invalid error serialization: 'The dto field is required.'

How to change database name in dbcontext connection string at runtime

My Asp.Net MVC application is setup as follows.
There are 4 projects in solution.
ge.Web
ge.BLL
ge.Core
ge.Entities
Controller in ge.Web initializes a repository object present in ge.Core
public class MapsController : Controller
{
private AssessmentRepository repAssessments = new AssessmentRepository("name=GEContext", schoolCode);
public ActionResult DisplaySearchResults()
{
.....
}
}
Assessments Repository
public class AssessmentRepository : Repository<Assessment>, IAssessmentRepository
{
public AssessmentRepository(string connString, string schoolCode)
:base(connString, schoolCode)
{ }
}
Repository
public class Repository<TEntity> : IRepository<TEntity> where TEntity:class
{
protected readonly GEContext context;
public Repository(string connString, string schoolCode) {
context = new GEContext(connString);
}
}
GEContext
public class GEContext : DbContext
{
public GEContext(string connString):base(connString)
{
this.Configuration.LazyLoadingEnabled = false;
Database.SetInitializer(new MySqlInitializer());
}
}
DbContext
public class DbContext : IDisposable, IObjectContextAdapter
{
public DbContext(string nameOrConnectionString);
}
Web.Config
<add name="GEContext" connectionString="server=localhost;port=4040;uid=root;pwd=xxx;database=ge" providerName="MySql.Data.MySqlClient" />
now i want to replace "database=ge" present in web.config with database=ge_[schoolCode]. at runtime How can i go about it?
UPDATE
My solution did not work. so i am stating the problem once again.
Web.Config
I have changed My config file to the following (previously GEContext was the only connection string)
<connectionStrings>
<add name="GEContext_sc001" connectionString="server=localhost;port=4040;uid=root;pwd=blabla;database=db_sc001" providerName="MySql.Data.MySqlClient" />
<add name="GEContext_sc002" connectionString="server=localhost;port=4040;uid=root;pwd=blabla;database=db" providerName="MySql.Data.MySqlClient" />
<appSettings>
<add key="SchoolCodes" value="sc001,sc002"/>
these are the allowed schoolCodes
Now when the user enters schoolcode at login screen, it is validated against the codes present in SchoolCodes key. and if yes, then it should try to connect to the connectionString for that particular connection. Now when my code comes to
UserManager.FindAsync
in Login function of AccountController, it crashes trying to find GEContext. Where is that set? and how can i change it?
I have changed the repository calling in controller as follows
private static string schoolCode = (string)System.Web.HttpContext.Current.Session["SchoolCode"];
private AssessmentRepository repAssessments = new AssessmentRepository("name=GEContext_" + schoolCode);
UPDATE-2
Following is present in ge.Web
IdentityConfig.cs
public class ApplicationUserManager : UserManager<ApplicationUser, int>
{
public ApplicationUserManager(IUserStore<ApplicationUser, int> store)
: base(store)
{
}
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(new UserStore<ApplicationUser, Role, int, UserLogin, UserRole, UserClaim>(context.Get<ApplicationDbContext>()));
...........
}
The following is present in ge.Core
ApplicationDbContext
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, Role, int, UserLogin, UserRole, UserClaim>
{
public ApplicationDbContext(string connString)
: base(connString)
{
Database.SetInitializer(new MySqlInitializer());
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext("name=GEContext_");
}
}
How can i pass schoolCode from ge.web to ge.Core (answer should be straight forward but currently i cant get my head around it)
UPDATE-3
As told by itikhomi and taking help from this post I have changed my code as follows
in ApplicationDbContext class added the following
public static ApplicationDbContext Create(string scCode){
return new ApplicationDbContext("name=GEContext_" + scCode);
}
in AccountController Login
var appDbContext = ApplicationDbContext.Create(model.SchoolCode);
Request.GetOwinContext().Set<ApplicationDbContext>(appDbContext);
it still does not hit the correct database
You have two ways
1)
using System.Data.SqlClient;
public class Repository<TEntity> : IRepository<TEntity> where TEntity:class
{
protected readonly GEContext context;
public Repository(string connString, string schoolCode) {
context = new GEContext(connString);
var connection = new SqlConnectionStringBuilder(context.Database.Connection.ConnectionString);
connection.InitialCatalog = "YOUR_PREFIX_FROMSOMEWHERE"+schoolCode;
context.Database.Connection.ConnectionString = connection.ConnectionString;
}
}
2) if you wants to switch connection when it opened before use ChangeDatabase:
//open connection if it close
context.Database.Connection.ChangeDatabase("DATABASE-NAME");
NOTE: if use ChangeDatabase connection should be already opened
FOR UPDATE3:
You need to do somethink like this:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public ApplicationDbContext(string schoolCode)
: base(schoolCode)
{
var connection = new SqlConnectionStringBuilder(this.Database.Connection.ConnectionString);
connection.InitialCatalog = "YOUR_PREFIX_FROMSOMEWHERE" + schoolCode;
this.Database.Connection.ConnectionString = connection.ConnectionString;
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
in account controller:
public ApplicationSignInManager SignInManager
{
get
{
if (_signInManager == null)
{
var code = HttpContext.Request.Form.Get("SchoolCode");//Get from FORM\QueryString\Session whatever you wants
if (code != null)
{
HttpContext.GetOwinContext().Set<ApplicationSignInManager>(new ApplicationSignInManager(_userManager, HttpContext.GetOwinContext().Authentication));
}
_signInManager = HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
}
return _signInManager;
}
private set
{
_signInManager = value;
}
}
public ApplicationUserManager UserManager
{
get
{
if (_userManager == null)
{
var code = HttpContext.Request.Form.Get("SchoolCode");//Get from FORM\QueryString\Session whatever you wants
if (code != null)
{
var appDbContext = new ApplicationDbContext(code);
HttpContext.GetOwinContext().Set<ApplicationDbContext>(appDbContext);
HttpContext.GetOwinContext().Set<ApplicationUserManager>(new ApplicationUserManager(new UserStore<ApplicationUser>(appDbContext))); //OR USE your specified create Method
}
_userManager = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
return _userManager;
}
private set
{
_userManager = value;
}
}
Your problem is in Store of UserManager is created before you change your OWIN context, in this case better to use DI like here
You can change the database for an open connection
context.Database.GetDbConnection().ChangeDatabase("");
I resolved it with the help of itikhomi..Posting the final code..
ApplicationDbContext
public static ApplicationDbContext Create()
{
return new ApplicationDbContext("name=GEContext");
}
AccountController
public ApplicationUserManager UserManager {
get
{
if (System.Web.HttpContext.Current.Session["SchoolCode"] == null)
return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
else
{
var appDbContext = ApplicationDbContext.Create(System.Web.HttpContext.Current.Session["SchoolCode"].ToString());//new ApplicationDbContext("name=GEContext", System.Web.HttpContext.Current.Session["SchoolCode"].ToString());
HttpContext.GetOwinContext().Set<ApplicationDbContext>(appDbContext);
HttpContext.GetOwinContext().Set<ApplicationUserManager>(new ApplicationUserManager(new UserStore<ApplicationUser, Role, int, UserLogin, UserRole, UserClaim>(appDbContext)));
return HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
}
private set
{
_userManager = value;
}
}

The entity type IdentityRole is not part of the model for the current context (MVC Role Manager)

I am pretty new to MVC. I am working role manager. Before this, I changed user id datatype to int from string. Now, I would like to have roles in my website. I have created page and added code to run that part. After running website, When I click on Create New User Role, I get this below error in background.
Here is my code:
private List<SelectListItem> GetAllRolesAsSelectList()
{
List<SelectListItem> SelectRoleListItems =
new List<SelectListItem>();
var roleManager =
new RoleManager<IdentityRole>(
new RoleStore<IdentityRole>(new ApplicationDbContext()));
var colRoleSelectList = roleManager.Roles.OrderBy(x => x.Name).ToList();
SelectRoleListItems.Add(
new SelectListItem
{
Text = "Select",
Value = "0"
});
foreach (var item in colRoleSelectList)
{
SelectRoleListItems.Add(
new SelectListItem
{
Text = item.Name.ToString(),
Value = item.Name.ToString()
});
}
return SelectRoleListItems;
}
This is the line where error is thrown
var roleManager =
new RoleManager<IdentityRole>(
new RoleStore<IdentityRole>(new ApplicationDbContext()));
Here is my IdentityModel page code:
public class CustomUserRole : IdentityUserRole<int>
{
}
public class CustomUserClaim : IdentityUserClaim<int>
{
}
public class CustomUserLogin : IdentityUserLogin<int>
{
}
public class CustomRole : IdentityRole<int, CustomUserRole>, IRole<int>
{
public CustomRole() : base() { }
public CustomRole(string name)
: this()
{
this.Name = name;
}
}
public class CustomUserStore : UserStore<ApplicationUser, CustomRole, int,
CustomUserLogin, CustomUserRole, CustomUserClaim>
{
public CustomUserStore(ApplicationDbContext context)
: base(context)
{
}
}
public class CustomRoleStore : RoleStore<CustomRole, int, CustomUserRole>
{
public CustomRoleStore(ApplicationDbContext context)
: base(context)
{
}
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, CustomRole,
int, CustomUserLogin, CustomUserRole, CustomUserClaim>
{
public ApplicationDbContext()
: base("SMSGoConnection")
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
Help would be appreciated.

aspnet identity using guid as key

I am trying to use Guid's instead of strings for my primary key and have followed the following posts: How to change type of id in Microsoft.AspNet.Identity.EntityFramework.IdentityUser and
How to change type of id in Microsoft.AspNet.Identity.EntityFramework.IdentityUser
I updated to the latest prerelease packages of aspnet identity
Microsoft ASP.NET Identity Core 2.0.0-beta1
Microsoft ASP.NET Identity EntityFramework 2.0.0-beta1
and edited my User to allow for Guid's instead of the default string, I then created my own dbContext and usermanager, however every time I try to login I get the following error:
System.Data.SqlClient.SqlException: Operand type clash:
uniqueidentifier is incompatible with int
for this line:
var user = await UserManager.FindAsync(model.UserName,
model.Password);
I have checked to make sure that all the fields in the database are definitely uniqueidentifiers and I'm not sure what to try next, below is the code I am currently using:
User objects:
public class GuidRole : IdentityRole<Guid, GuidUserRole>
{
public GuidRole()
{
Id = Guid.NewGuid();
}
public GuidRole(string name) : this() { Name = name; }
}
public class GuidUserRole : IdentityUserRole<Guid> { }
public class GuidUserClaim : IdentityUserClaim<Guid> { }
public class GuidUserLogin : IdentityUserLogin<Guid> { }
public class User : IdentityUser<Guid, GuidUserLogin, GuidUserRole, GuidUserClaim>
{
public User()
{
Id = Guid.NewGuid();
}
public User(string name) : this() { UserName = name; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
dbContext:
public class newDbContext : IdentityDbContext<User, GuidRole, Guid, GuidUserLogin, GuidUserRole, GuidUserClaim>
{
public newDbContext()
: base(nameOrConnectionString: "defaultConnection") { }
public newDbContext(string connectionString)
: base(nameOrConnectionString: connectionString) { }
static newDbContext()
{
Database.SetInitializer<newDbContext>(null);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Use singular table names
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<User>().ToTable("User").Property(p => p.Id).HasColumnName("UserID");
modelBuilder.Entity<User>().Property(p => p.Email).HasColumnName("EmailAddress");
modelBuilder.Entity<GuidUserRole>().HasKey(r => new { r.RoleId, r.UserId });
modelBuilder.Entity<GuidUserRole>().ToTable("UserRole");
modelBuilder.Entity<GuidUserRole>().Property(r => r.UserId).HasColumnName("UserID");
modelBuilder.Entity<GuidUserRole>().Property(r => r.RoleId).HasColumnName("RoleID");
modelBuilder.Entity<GuidUserLogin>().ToTable("UserLogin");
modelBuilder.Entity<GuidUserLogin>().Property(r => r.UserId).HasColumnName("UserID");
modelBuilder.Entity<GuidUserClaim>().ToTable("UserClaim");
modelBuilder.Entity<GuidUserClaim>().Property(r => r.Id).HasColumnName("UserClaimID");
modelBuilder.Entity<GuidRole>().HasKey<Guid>(r => r.Id);
modelBuilder.Entity<GuidRole>().ToTable("Role");
modelBuilder.Entity<GuidRole>().Property(r => r.Id).HasColumnName("RoleID");
Configuration.ProxyCreationEnabled = false;
Configuration.LazyLoadingEnabled = false;
}
}
and finally the user manager:
public class ApplicationUserManager : UserManager<User, Guid>
{
public ApplicationUserManager(string connectionString)
: base(new UserStore<User, GuidRole, Guid, GuidUserLogin, GuidUserRole, GuidUserClaim>(new newDbContext()))
{
UserValidator = new UserValidator<User, Guid>(this) { AllowOnlyAlphanumericUserNames = false };
}
}
Thanks to Hao Kung's comment I individually went through the table and property mappings until I got to the UserClaims table. Turns out I had the field type set to uniqueidentifier in the database, however this still needed to be an int. Changing it fixed the problem!

StructureMap Question

This is the equivalent of what I'm trying to create with StructureMap:
new ChangePasswordWithNotificationAndLoggingService(
new ChangePasswordService(
new ActiveDirectoryRepository(new ActiveDirectoryCredentials()),
new TokenRepository("")),
new EmailNotificationService(new PasswordChangedNotification(new UserAccount())),
new LoggingService());
This is what I have right now:
ForRequestedType<IChangePasswordService>()
.TheDefault.Is.ConstructedBy(() =>
new ChangePasswordService(DependencyRegistrar.Resolve<IActiveDirectoryRepository>(),
DependencyRegistrar.Resolve<ITokenRepository>()))
.EnrichWith<IChangePasswordService>(x =>
new ChangePasswordWithNotificationAndLoggingService(x,
DependencyRegistrar.Resolve<INotificationService>(),
DependencyRegistrar.Resolve<ILoggingService>()));
I need to pass the UserAccount to the INotificationService...can't figure it out.
I've tried this:
DependencyRegistrar.With(new UserAccount { Username = "test" });
No luck...UserAccount always turns out null. I don't have to do it all with StructureMap, I'm open to any suggestions.
This is what I currently have working:
public static IChangePasswordService ChangePasswordService(UserAccount userAccount)
{
return new ChangePasswordWithNotificationService(
new ChangePasswordService(ActiveDirectoryRepository(), TokenRepository()),
new EmailNotificationService(new PasswordChangedNotification(userAccount)));
}
Have you tried just using AutoWiring? These are all concrete classes with simple construction so StructureMap can figure out what you need.
For<IChangePasswordService>().Use<ChangePasswordService>();
Looking at your construction I think that this simple configuration might just work.
Edit
Regarding the comments.
You should use the With(T instance) method to have the container construct your IChangePasswordService using the given userAccount.
var userAccount = new UserAccount("derans");
var changePasswordService = container.With(userAccount).GetInstance<IChangePasswordService>();
Why not encapsulate the creation of the change password service into a factory - the factory is then an implemented as StructureMap factory that use a UserAccount passed in and the 'ObjectFactory' to create instances of the IIChangePasswordService as required?
I have demo'ed it below:
namespace SMTest
{
class Program
{
static void Main(string[] args)
{
// bootstrapper...
ObjectFactory.Configure(x => x.AddRegistry(new TestRegistry()));
// create factory for use later (IoC manages this)...
var changePasswordServiceFactory = ObjectFactory.GetInstance<IChangePasswordServiceFactory>();
var daveAccount = new UserAccount("Dave Cox");
var steveAccount = new UserAccount("Steve Jones");
var passwordService1 = changePasswordServiceFactory.CreateForUserAccount(daveAccount);
var passwordService2 = changePasswordServiceFactory.CreateForUserAccount(steveAccount);
}
}
public class TestRegistry : Registry
{
public TestRegistry()
{
Scan(x =>
{
x.TheCallingAssembly();
x.AssemblyContainingType(typeof(IChangePasswordService));
x.AssemblyContainingType(typeof(IActiveDirectoryRepository));
x.AssemblyContainingType(typeof(IActiveDirectoryCredentials));
x.AssemblyContainingType(typeof(ITokenRepository));
x.AssemblyContainingType(typeof(INotification));
x.AssemblyContainingType(typeof(INotificationService));
x.AssemblyContainingType(typeof(ILoggingService));
ForRequestedType<ILoggingService>().TheDefault.Is.OfConcreteType<MyLogger>();
ForRequestedType<IActiveDirectoryRepository>().TheDefault.Is.OfConcreteType<MyAdRepository>();
ForRequestedType<IActiveDirectoryCredentials>().TheDefault.Is.OfConcreteType<MyAdCredentials>();
ForRequestedType<ITokenRepository>().TheDefault.Is.OfConcreteType<MyTokenRepository>();
ForRequestedType<IChangePasswordService>().TheDefault.Is.OfConcreteType<ChangePasswordService>();
ForRequestedType<IChangePasswordServiceFactory>().CacheBy(InstanceScope.Singleton).TheDefault.Is.OfConcreteType<StructureMapChangePasswordServiceFactory>();
ForRequestedType<INotification>().TheDefault.Is.OfConcreteType<MyPasswordChangedNotification>();
ForRequestedType<INotificationService>().TheDefault.Is.OfConcreteType<MyEmailNotificationService>();
});
}
}
public interface ILoggingService
{
}
public class MyLogger : ILoggingService
{
}
public class UserAccount
{
public string Name { get; private set; }
public UserAccount(string name)
{
Name = name;
}
}
public interface INotification
{
}
public class MyPasswordChangedNotification : INotification
{
private readonly UserAccount _account;
private readonly ILoggingService _logger;
public MyPasswordChangedNotification(UserAccount account, ILoggingService logger)
{
_account = account;
_logger = logger;
}
}
public interface INotificationService
{
}
public class MyEmailNotificationService : INotificationService
{
private readonly INotification _notification;
private readonly ILoggingService _logger;
public MyEmailNotificationService(INotification notification, ILoggingService logger)
{
_notification = notification;
_logger = logger;
}
}
public interface ITokenRepository
{
}
public class MyTokenRepository : ITokenRepository
{
}
public interface IActiveDirectoryRepository
{
}
public interface IActiveDirectoryCredentials
{
}
public class MyAdCredentials : IActiveDirectoryCredentials
{
}
public class MyAdRepository : IActiveDirectoryRepository
{
private readonly IActiveDirectoryCredentials _credentials;
public MyAdRepository(IActiveDirectoryCredentials credentials)
{
_credentials = credentials;
}
}
public interface IChangePasswordService
{
}
public class ChangePasswordService : IChangePasswordService
{
private readonly IActiveDirectoryRepository _adRepository;
private readonly ITokenRepository _tokenRepository;
private readonly INotificationService _notificationService;
public ChangePasswordService(IActiveDirectoryRepository adRepository, ITokenRepository tokenRepository, INotificationService notificationService)
{
_adRepository = adRepository;
_tokenRepository = tokenRepository;
_notificationService = notificationService;
}
}
public interface IChangePasswordServiceFactory
{
IChangePasswordService CreateForUserAccount(UserAccount account);
}
public class StructureMapChangePasswordServiceFactory : IChangePasswordServiceFactory
{
public IChangePasswordService CreateForUserAccount(UserAccount account)
{
return ObjectFactory.With(account).GetInstance < IChangePasswordService>();
}
}
}

Resources