Entity Framework: Why SimpleMembership looking for Default Connection - asp.net-mvc

I have explicitly set AccountsContext to use mytestdb as the connection string for SimpleMembership, as below -
public class AccountsContext : DbContext
{
public AccountsContext()
: base("mytestdb")
{
}
}
But Database initialized in following line of code is still looking for DefaultConnection for some reason. Although I have removed reference to DefaultConnection completely from web.config.
public sealed class InitializeSimpleMembershipAttribute : ActionFilterAttribute
{
private static SimpleMembershipInitializer _initializer;
private static object _initializerLock = new object();
private static bool _isInitialized;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Ensure ASP.NET Simple Membership is initialized only once per app start
LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);
}
}
Here is the Web.config file with commented sections -
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<!--<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=4.4.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />-->
</configSections>
<connectionStrings>
<add name="mytestdb" connectionString="Data Source=(local);Initial Catalog=mytestdb;User ID=****;Password=****" providerName="System.Data.SqlClient" />
<!--<add name="DefaultConnection"
connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=aspnet-LakshyaMvc-20130205074346;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnet-***.mdf"
providerName="System.Data.SqlClient" />-->
</connectionStrings>
<!--<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
</entityFramework>-->
Any help in this regard will be much helpful.

Take a look at the SimpleMembershipInitializer private class inside the ~/Filters/InitializeSimpleMembershipAttribute.cs file:
private class SimpleMembershipInitializer
{
public SimpleMembershipInitializer()
{
Database.SetInitializer<UsersContext>(null);
try
{
using (var context = new UsersContext())
{
if (!context.Database.Exists())
{
// Create the SimpleMembership database without Entity Framework migration schema
((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
}
}
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
}
catch (Exception ex)
{
throw new InvalidOperationException("The ASP.NET Simple Membership database could not be initialized. For more information, please see http://go.microsoft.com/fwlink/?LinkId=256588", ex);
}
}
}
Do you notice the following line:
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
That's where it is coming from. By the way if you had looked at the exception stacktrace you got it would have pointed you to this location.
Also in the ~/Models/AccountModel.cs file you might have the following context defined by default:
public class UsersContext : DbContext
{
public UsersContext()
: base("DefaultConnection")
{
}
public DbSet<UserProfile> UserProfiles { get; set; }
}

Related

WF Unity or another way for IoC/DI

Good evening everyone.
Currently, I'm new person in IoC/DI. I have a Winform project with C#. Please view some codes and help me resolve below issue:
1/ IRepository
namespace Framework.Repositories
{
public interface IRepository<T> : IDisposable where T:class
{
T Get(int id);
IEnumerable<T> GetAll();
IEnumerable<T> Find(Expression<Func<T, bool>> predicate);
}
}
2/ Repository
namespace Framework.Repositories
{
public class Repository<T> : IRepository<T> where T : class
{
private bool _disposed = false;
private static bool _isTransactionStarted;
protected readonly DbContext Context;
private DbContextTransaction _transaction { get; set; }
public Repository(DbContext context)
{
Context = context;
_isTransactionStarted = false;
if (context == null)
throw new NullReferenceException(nameof(context));
if (Context.Set<T>() == null)
throw new NullReferenceException("_context.Set<T>()");
}
public T Get(int id) => Context.Set<T>().Find(id);
public IEnumerable<T> GetAll() => Context.Set<T>().ToList();
public IEnumerable<T> Find(Expression<Func<T, bool>> predicate) => Context.Set<T>().Where(predicate);
}
}
3/ Model
namespace PRO.Model
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
[Table("Employee")]
public partial class Employee
{
[Key]
public long EmpId { get; set; }
[StringLength(15)]
public string Username { get; set; }
public string Password { get; set; }
[StringLength(50)]
public string UserGroup { get; set; }
[Required]
[StringLength(50)]
public string FirstName { get; set; }
[StringLength(50)]
public string LastName { get; set; }
[Required]
[StringLength(1)]
public string EmpStatus { get; set; }
}
}
4/ IEmployeeRepository
namespace PRO.Repositories
{
public interface IEmployeeRepository:IRepository<Employee>
{
Employee UserLogin(string username, string password);
}
}
5/ EmployeeRepository
namespace PRO.Repositories
{
public class EmployeeRepository : Repository<Employee>,IEmployeeRepository
{
public EmployeeRepository(DbContext context) : base(context)
{
}
public Employee UserLogin(string username, string password)
{
try
{
return Find(x=>x.Username == username && x.Password == password && x.EmpStatus == BooleanType.Yes ).FirstOrDefault();
}
catch (Exception ex)
{
throw new RepositoryException(ex);
}
}
public MyDbContext myDbContext => Context as MinhTamHotelDbContext;
}
}
6/ IEmployeeService
namespace PRO.Services
{
public interface IEmployeeService
{
Employee UserLogin(string username, string password);
}
}
7/ EmployeeService
namespace PRO.Services
{
public class EmployeeService : IEmployeeService
{
public IEmployeeRepository EmployeeRepos { get; set; }
public Employee UserLogin(string username, string password)
{
return EmployeeRepos.UserLogin(username, password);
}
}
}
8/ DbContext
namespace PRO.Repositories
{
using System.Data.Entity;
public partial class MyHotelDbContext: DbContext
{
public MyHotelDbContext()
: base("name=MyHotelDbContext")
{
}
public virtual DbSet<Employee> Employees { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//DbContext Here
}
}
}
9/App.config
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration, Version=2.1.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</configSections>
<connectionStrings>
<add name="MinhTamHotelDbContext" connectionString="data source=.;initial catalog=WiF;persist security info=True;user id=sa;password=#success#;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />
</connectionStrings>
<alias alias="transient" type="Microsoft.Practices.Unity.TransientLifetimeManager, Microsoft.Practices.Unity, Version=2.1.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<alias alias="perResolve" type="Microsoft.Practices.Unity.PerResolveLifetimeManager, Microsoft.Practices.Unity, Version=2.1.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<alias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager, Microsoft.Practices.Unity, Version=2.1.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<alias alias="AreaRepository" type="PRO.Repositories.AreaRepository, PRO.Repositories, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<alias alias="IAreaRepository" type="PRO.Repositories.IAreaRepository, PRO.Repositories, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<alias alias="EmployeeRepository" type="PRO.Repositories.EmployeeRepository, PRO.Repositories, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<alias alias="IEmployeeRepository" type="PRO.Repositories.IEmployeeRepository, PRO.Repositories, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<alias alias="GnrlCodeRepository" type="PRO.Repositories.GnrlCodeRepository, PRO.Repositories, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<alias alias="IGnrlCodeRepository" type="PRO.Repositories.IGnrlCodeRepository, PRO.Repositories, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<alias alias="AreaService" type="PRO.Services.AreaService, PRO.Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<alias alias="IAreaService" type="PRO.Services.IAreaService, PRO.Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<alias alias="EmployeeService" type="PRO.Services.EmployeeService, PRO.Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<alias alias="IEmployeeService" type="PRO.Services.IEmployeeService, PRO.Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<alias alias="GnrlCodeService" type="PRO.Services.GnrlCodeService, PRO.Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<alias alias="IGnrlCodeService" type="PRO.Services.IGnrlCodeService, PRO.Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<alias alias="IRepository" type="Framework.Repositories.IRepository, Framework.Repositories, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<alias alias="Repository" type="Framework.Repositories.Repository, Framework.Repositories, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<container>
<register type="IAreaRepository" mapTo="AreaRepository">
<lifetime type="perResolve" />
</register>
<register type="IEmployeeRepository" mapTo="EmployeeRepository">
<lifetime type="perResolve" />
</register>
<register type="IGnrlCodeRepository" mapTo="GnrlCodeRepository">
<lifetime type="perResolve" />
</register>
<register type="IEmployeeService" mapTo="EmployeeService">
<property name="EmployeeRepos" dependencyType="IEmployeeRepository" />
<lifetime type="perResolve" />
</register>
<register type="IGnrlCodeService" mapTo="GnrlCodeService">
<property name="GnrlCodeRepos" dependencyType="IGnrlCodeRepository" />
<lifetime type="perResolve" />
</register>
<register type="IAreaService" mapTo="AreaService">
<property name="AreaRepos" dependencyType="IAreaRepository" />
<lifetime type="perResolve" />
</register>
</container>
10/ In my login form
public partial class UserLogin : Form
{
private IEmployeeService _employeeSvr = null;
public IEmployeeService EmployeeSrv
{
get { return _employeeSvr ?? (_employeeSvr = UnityInstanceProvider.CreateInstance<IEmployeeService>()); }
set { _employeeSvr = value; }
}
private void btnLogin_Click(object sender, System.EventArgs e)
{
try
{
this.Cursor = Cursors.WaitCursor;
var employee = EmployeeSrv.UserLogin(txtUsername.Text.TrimEx(), txtPassword.Text.TrimEx());
//MsgBox.ShowInfoMsg(employee.ToJsonObject().ToStringEx());
if (employee != null)
{
Visible = false;
AreaMap.Instance.Show();
}
}
catch (Exception ex)
{
ex.ExceptionHandler();
}
finally
{
this.Cursor = Cursors.Default;
}
}
}
My Error is:
Resolution of the dependency failed, type = "PRO.Services.IEmployeeService", name = "(none)".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The type DbConnection does not have an accessible constructor.
-----------------------------------------------
At the time of the exception, the container was:
Resolving PRO.Services.EmployeeService,(none) (mapped from PRO.Services.IEmployeeService, (none))
Resolving value for property EmployeeService.EmployeeRepos
Resolving PRO.Repositories.EmployeeRepository,(none) (mapped from PRO.Repositories.IEmployeeRepository, (none))
Resolving parameter "context" of constructor PRO.Repositories.EmployeeRepository(System.Data.Entity.DbContext context)
Resolving System.Data.Entity.DbContext,(none)
Resolving parameter "existingConnection" of constructor System.Data.Entity.DbContext(System.Data.Common.DbConnection existingConnection, System.Data.Entity.Infrastructure.DbCompiledModel model, System.Boolean contextOwnsConnection)
Resolving System.Data.Common.DbConnection,(none)
Somebody can help me resolve this problem ?
In case Unity doesn't support multiple inheritance (EmployeeRepository: Repository, IEmployeeRepository), Have another way to replace Unity ?
Thank you so much

EntityFramework Code first migrations not running after deploying to Azure

I'm developing a web application in ASP.NET using code first migrations. It works fine locally but after deploying to Azure, code first migrations are not executed. I have been following this tutorial step by step a few times but I have not been able to spot what is wrong on my setup. Here is the relevant code:
DB Context:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext() : base("DefaultConnection", throwIfV1Schema: false) {}
public DbSet<BC_Instance> BiocloudInstances { get; set; }
static ApplicationDbContext() {}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
var conv = new AttributeToTableAnnotationConvention<SoftDeleteAttribute, string>(
"SoftDeleteColumnName",
(type, attributes) => attributes.Single().ColumnName);
modelBuilder.Conventions.Add(conv);
}
}
Connection strings:
(it is replaced on publish, but just in case)
<add name="DefaultConnection" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=bcplatform2;Integrated Security=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" /></connectionStrings>
Code First Migrations configuration
internal sealed class Configuration : DbMigrationsConfiguration<bcplatform2.Models.ApplicationDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(bcplatform2.Models.ApplicationDbContext context)
{
var userManager = new ApplicationUserManager(new UserStore<ApplicationUser>(context));
var roleManager = new ApplicationRoleManager(new RoleStore<ApplicationRole>(context));
const string name = {name here};
const string password = {pass here};
const string adminRole = {role};
string[] roles = new string[] { adminRole, ApplicationRole.DefaultRoleName };
foreach (string role in roles)
{
if (!context.Roles.Any(r => r.Name == role))
{
roleManager.CreateAsync(new ApplicationRole(role));
}
}
if (!context.Users.Any(u => u.UserName == name))
{
var user = new ApplicationUser { UserName = name, Email = name, credit = 10 };
userManager.Create(user, password);
userManager.AddToRole(user.Id, adminRole);
userManager.SetLockoutEnabled(user.Id, false);
}
}
}
Publication wizard
Entity framework section in deployed Web.config
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="mssqllocaldb" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
<contexts>
<context type="bcplatform2.Models.ApplicationDbContext, bcplatform2">
<databaseInitializer type="System.Data.Entity.MigrateDatabaseToLatestVersion`2[[bcplatform2.Models.ApplicationDbContext, bcplatform2], [bcplatform2.Migrations.Configuration, bcplatform2]], EntityFramework, PublicKeyToken={token}">
<parameters>
<parameter value="DefaultConnection_DatabasePublish" />
</parameters>
</databaseInitializer>
</context>
</contexts>
</entityFramework>
Connection strings in deployed Web.config
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=tcp:{serverid}.database.windows.net,1433;Initial Catalog={dbid};User Id={user};Password={password}" providerName="System.Data.SqlClient" />
<add name="DefaultConnection_DatabasePublish" connectionString="Data Source=tcp:{serverid}.database.windows.net,1433;Initial Catalog={dbid};User ID={user};Password={password}" providerName="System.Data.SqlClient" />
</connectionStrings>
You can update your Web.config file in Solution
It's not necessary provide connection string inside "context" section, because you already provide it in ApplicationDbContext constructor.
Also, with this config, you can uncheck "Execute code first migration" in Publication Wizard.
Your EF section should look similar to this (most important is "context" section):
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="mssqllocaldb" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
<contexts>
<context type="TestWebApp.Models.AppContext, TestWebApp">
<databaseInitializer type="System.Data.Entity.MigrateDatabaseToLatestVersion`2[[TestWebApp.Models.AppContext, TestWebApp], [TestWebApp.Migrations.Configuration, TestWebApp]], EntityFramework" />
</context>
</contexts>
It is not working because you might have created/selected other connection in deploy wizard. Same is confirmed in the deployed connection string where you can see two connnection strings.
The second connection string is also referecened in EF seciton -
And, in the context you have used first connectionstring - public ApplicationDbContext() : base("DefaultConnection", throwIfV1Schema: false) {}
Changing name here will solve your issue.
if you want to have more control on the migration process you can handle the migration in the Startup.Auth by creating the context and use the DBMigrator() class to apply any pending migration:
//Get the connection string
var connectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"];
//Instanciate the sql connection string builder
var builder = new System.Data.SqlClient.SqlConnectionStringBuilder(connectionString.ConnectionString);
//Create your context
var dbContext = new ApplicationDbContext(builder.ConnectionString);
//Check for null (Handle issue here).
if (dbContext == null) return;
//Get your configuration and specify the target database
var config = new Migrations.Configuration();
config.TargetDatabase = new DbConnectionInfo(builder.ConnectionString, "System.Data.SqlClient");
//Create the migrator using your config
var mig = new DbMigrator(config);
//Check for any pending migration to speed up the process and Update
//The migration will be applied here each time the application is published on azure
if(mig.GetPendingMigrations().Any())mig.Update();
While this may not solve your issue directly, it allow more control and you should be able to see if the migration is not applied with a little debbuging.
The problem was on the seed method:
protected override void Seed(bcplatform2.Models.ApplicationDbContext context)
{
var userManager = new ApplicationUserManager(new UserStore<ApplicationUser>(context));
var roleManager = new ApplicationRoleManager(new RoleStore<ApplicationRole>(context));
const string name = {name here};
const string password = {pass here};
const string adminRole = {role};
string[] roles = new string[] { adminRole, ApplicationRole.DefaultRoleName };
foreach (string role in roles)
{
if (!context.Roles.Any(r => r.Name == role))
{
roleManager.CreateAsync(new ApplicationRole(role));
}
}
if (!context.Users.Any(u => u.UserName == name))
{
var user = new ApplicationUser { UserName = name, Email = name, credit = 10 };
userManager.Create(user, password);
userManager.AddToRole(user.Id, adminRole);
userManager.SetLockoutEnabled(user.Id, false);
}
}
It did not complete but didn't show any error on the publication output making the error difficult to spot. I removed the seed method and the migrations worked.
Some advice to avoid similar problems in the future would be not use the "Use this connection string at runtime" and "Execute code first migrations" options from the publication wizard. If something goes wrong the output won't always show an error and it gives little control over how Web.config is modified.
Instead, replace the connection string in Web.config before publishing or configure the Web.Debug.config and Web.Release.config accordingly.

IChartStorageHandler implementation, handler does not trigger

I'm trying to implement IChartStorageHandler via .Net4.5/MVC4 application to use on Azure based on http://goo.gl/WAapl
I couldn't be able to hit none of the breakpoints that I set in the class below. So my question is, "is there any trick that I can use to force it"? Thank you!
You may find the details about the parameters at http://msdn.microsoft.com/en-us/library/dd456629.aspx
namespace MvcWebRole1.Codes
{
public class ChartImageHandler : IChartStorageHandler
{
public ChartImageHandler()
{
throw new NotImplementedException();
}
#region IChartStorageHandler Members
public void Delete(string key)
{
throw new NotImplementedException();
}
public bool Exists(string key)
{
throw new NotImplementedException();
}
public byte[] Load(string key)
{
throw new NotImplementedException();
}
public void Save(string key, byte[] data)
{
throw new NotImplementedException();
}
#endregion
}
}
web.config part #1
<appSettings>
<add key="ChartImageHandler" value="handler=MvcWebRole1.Codes.ChartImageHandler, MvcWebRole1; webDevServerUseConfigSettings=false;" />
</appSettings>
web.config part #2
<system.webServer>
<handlers>
<remove name="ChartImageHandler"/>
<add name="ChartImageHandler" path="ChartImg.axd" verb="GET,HEAD,POST" type="System.Web.UI.DataVisualization.Charting.ChartHttpHandler, System.Web.DataVisualization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode" />
</handlers>
</system.webServer>
controller
public ActionResult ChartImage()
{
// get data
string path = HttpContext.Server.MapPath("~/App_Data/Test.csv");
IEnumerable<Bar> data = BarRepository.Get(path);
// generate chart
byte[] chartResult = data.Generator();
// return the chart
return File(chartResult, "image/png");
}
public static class ChartOperations
{
private static Chart _chart1;
public static byte[] Generator(this IEnumerable<Bar> data)
{
// initial variable tasks
_chart1 = new Chart() {DataSource = data.ToList()};
// generate the chart
DoTheHardWork();
// save chart to memory string
var image = new MemoryStream();
_chart1.SaveImage(image);
var result = image.GetBuffer();
return result;
}
}
Can you check if you have any entries for ChartImageHandler under system.web/httpHandlers? If yes, then please remove it.
also, it might not relate to this but in you web.config part #1, shouldn't you mention storage=file; as well so as to make it look like :
<add key="ChartImageHandler" value="storage=file;handler=MvcWebRole1.Codes.ChartImageHandler, MvcWebRole1; webDevServerUseConfigSettings=false;" />
This might be a stupid question to ask but when you are trying to hit a break point in your handler are you actually opening a page that includes ASP.NET Charts? The Chart handler will be hit only when charts are being loaded.
Perhaps you could launch the debugger as soon as your class is created?
public ChartImageHandler()
{
System.Diagnostics.Debugger.Launch();
//throw new NotImplementedException();
}
More at http://msdn.microsoft.com/en-us/library/system.diagnostics.debugger.launch.aspx

I can't set up a connection string for ASP.Net MVC v4.0 with standard method of Authentication

Please I need help with this scenario:
I want to use the default ASP Membership/Authentication in my MVC app, connected to a VPN.
In web.config I setup the connection "MyCustomConnection":
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=4.4.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<connectionStrings>
...
<add name="MyCustomConnection" connectionString="Data Source=172.x.x.y\somewhere;Initial Catalog=The.Main.DB;User ID=sa;Password=sapass;Trusted_Connection=True;Integrated Security=SSPI" providerName="System.Data.SqlClient" />
</connectionStrings>
Then in InitializeSimpleMembershipAttribute I have:
public sealed class InitializeSimpleMembershipAttribute : ActionFilterAttribute
{
private static SimpleMembershipInitializer _initializer;
private static object _initializerLock = new object();
private static bool _isInitialized;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Ensure ASP.NET Simple Membership is initialized only once per app start
LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);
}
private class SimpleMembershipInitializer
{
public SimpleMembershipInitializer()
{
Database.SetInitializer<UsersContext>(null);
try
{
using (var context = new UsersContext())
{
if (!context.Database.Exists())
{
// Create the SimpleMembership database without Entity Framework migration schema
((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
}
}
WebSecurity.InitializeDatabaseConnection("MyCustomConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
}
catch (Exception ex)
{
throw new InvalidOperationException("The ASP.NET Simple Membership database could not be initialized. For more information, please see http://go.microsoft.com/fwlink/?LinkId=256588", ex);
}
}
}
}
When the debugger hit(After a click in the Login Hyperlink of the Basic Template) WebSecurity.InitializeDatabaseConnection("MyCustomConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true), threw an exception:
Cannot open database "The.Main.DB" requested by the login. The login failed.
Login failed for user 'VPN\MYUSER'.
Additionally in User Context:
public class UsersContext : DbContext
{
public UsersContext()
: base("MyCustomConnection")
{
}
public DbSet<UserProfile> UserProfiles { get; set; }
}
My question is:
Why WebSecurity.InitializeDatabaseConnection("MyCustomConnection",... is trying to connect with the user of vpn and no with 'sa'(and his password 'sapass') as my connection string.
Thanks.
The issue is with the connection string, specifically the use of Trusted_Connection=True;Integrated Security=SSPI for more information, check here: Difference between Integrated Security = True and Integrated Security = SSPI

Extending ClaimsIdentity in MVC3

I've got my claims set-up with MVC3 using azure and everything is going well.
What I need to do now is extend the Claims Identity that's in the current thread / http context and add my own information (DOB, Address.. that sort of stuff)
so my question is - where is the best place to do this? any examples would be great..
I presume that when the user is authenticated id then have to go to the DB and pull back the relevant record for the user then add it to the custom Claims Identity object?
Typically you will have a httpmodule that will inspect the cookies and once the FedAuth token is found, you have a hook to build your Claims Principal and identities.
You don't typically need to store the user's entire profile, just useful things that wont typically change that often. I do this inside of an actionfilter.
Here is the code I found that does all of this.
https://github.com/wcpro/ScaffR/tree/master/src/ScaffR.Security/content/CodeTemplates/Scaffolders/ScaffR.Security
You may have to do a little digging but its all there.
Here is the code for the http module
public class ClaimsTransformationHttpModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.PostAuthenticateRequest += context_PostAuthenticateRequest;
}
void context_PostAuthenticateRequest(object sender, EventArgs e)
{
var context = ((HttpApplication) sender).Context;
if (FederatedAuthentication.SessionAuthenticationModule != null &&
FederatedAuthentication.SessionAuthenticationModule.ContainsSessionTokenCookie(context.Request.Cookies))
{
return;
}
var transformer = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.ClaimsAuthenticationManager;
if (transformer != null)
{
var transformedPrincipal = transformer.Authenticate(context.Request.RawUrl, context.User as ClaimsPrincipal);
context.User = transformedPrincipal;
Thread.CurrentPrincipal = transformedPrincipal;
}
}
public void Dispose() { }
}
Here is the Claims Transformer
public partial class ClaimsTransformer : ClaimsAuthenticationManager
{
partial void SetCustomPrincipalClaims(IUserService userService, ref ClaimsPrincipal principal);
public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
{
if (!incomingPrincipal.Identity.IsAuthenticated)
{
return incomingPrincipal;
}
var newPrincipal = Transform(incomingPrincipal);
EstablishSession(newPrincipal);
return newPrincipal;
}
ClaimsPrincipal Transform(ClaimsPrincipal incomingPrincipal)
{
var nameClaim = incomingPrincipal.Identities.First().FindFirst(ClaimTypes.Name);
var userService = DependencyResolver.Current.GetService<IUserService>();
var user = userService.GetByUsername(nameClaim.Value);
var id = new ApplicationIdentity(user);
var principal = new ClaimsPrincipal(id);
SetCustomPrincipalClaims(userService, ref principal);
return principal;
}
private void EstablishSession(ClaimsPrincipal principal)
{
if (HttpContext.Current != null)
{
var sessionToken = new SessionSecurityToken(principal);
FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionToken);
}
}
}
Then here is the configuration
<?xml version="1.0" encoding="utf-8"?>
<system.identityModel>
<identityConfiguration>
<claimsAuthenticationManager type="Barbarella.Core.Common.Security.ClaimsTransformer, Barbarella.Core" />
</identityConfiguration>
</system.identityModel>
And this...
<system.identityModel.services>
<federationConfiguration>
<cookieHandler mode="Default" requireSsl="false" />
</federationConfiguration>
</system.identityModel.services>
And this...
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="true">
<add name="ClaimsTransformationModule" type="Barbarella.Core.Common.Security.ClaimsTransformationHttpModule, Barbarella.Core" />
<add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</modules>
Dont forget to add your configuration sections
<section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
<section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
Here is my code for the ApplicationIdentity (overrides ClaimsIDentity)... This is the code that answers your question really...
public sealed partial class ApplicationIdentity : ClaimsIdentity
{
partial void SetCustomIdentityClaims(User user);
private readonly User _user;
public ApplicationIdentity(User user) : base("Application")
{
_user = user;
AddClaim(new Claim(ClaimTypes.Name, user.Username));
AddClaim(new Claim(ApplicationClaimTypes.UserId, user.Id.ToString(CultureInfo.InvariantCulture)));
AddClaim(new Claim(ApplicationClaimTypes.FirstName, user.FirstName));
AddClaim(new Claim(ApplicationClaimTypes.LastName, user.LastName));
AddClaim(new Claim("Time", DateTime.Now.ToString()));
SetCustomIdentityClaims(_user);
}
public User User
{
get { return _user; }
}
public int UserId
{
get { return int.Parse(FindFirst(ApplicationClaimTypes.UserId).Value); }
}
public string Username
{
get { return FindFirst(ClaimTypes.Name).Value; }
}
}

Resources