The data protection operation was unsuccessful on azure with autofac - c#

I have been getting this error when trying to create or update a user.
The full error is:
The data protection operation was unsuccessful. This may have been caused by not having the user profile loaded for the current thread's user context, which may be the case when the thread is impersonating.
We use autofac in our application, so I after reading this article I created my own IdentityFactoryOptions like this:
public class IdentityFactoryOptions: IdentityFactoryOptions<UserProvider>
{
public IdentityFactoryOptions()
{
DataProtectionProvider = new DpapiDataProtectionProvider("ASP.NET Identity");
}
}
and then I created my own DataProtectionTokenProvider like this:
public class DataProtectionTokenProvider : DataProtectorTokenProvider<User>
{
public DataProtectionTokenProvider(IdentityFactoryOptions options) : base(options.DataProtectionProvider.Create("ASP.NET Identity"))
{
TokenLifespan = TimeSpan.FromHours(6);
}
}
I registered both these as SingleInstances like this:
builder.RegisterType<IdentityFactoryOptions>().AsSelf().SingleInstance();
builder.RegisterType<DataProtectionTokenProvider>().AsSelf().SingleInstance();
and I injected the DataProtectionTokenProvider into my UserManager and assigned it in the managers constructor like this:
UserTokenProvider = dataProtectionTokenProvider;
But after doing all this, I still get the error.
I also read this article and saw you have to update your web.config too, so I added this:
<system.identityModel>
<identityConfiguration>
<securityTokenHandlers>
<add type="System.IdentityModel.Services.Tokens.MachineKeySessionSecurityTokenHandler, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<remove type="System.IdentityModel.Tokens.SessionSecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</securityTokenHandlers>
</identityConfiguration>
</system.identityModel>
But the error persists.
Does anyone have any solution for this? It is driving me mad....

Ok, I managed to fix this.
Using the first post I linked, I injected the IAppBuilder into my autofac module and removed my IdentityFactoryOptions class. So the registration now looks like this:
builder.Register(m => new DataProtectorTokenProvider(_app.GetDataProtectionProvider())).AsSelf().SingleInstance();
And the DataProtectorTokenProvider looks like this:
public class DataProtectorTokenProvider : DataProtectorTokenProvider<User>
{
public DataProtectorTokenProvider(IDataProtectionProvider dataProtectionProvider) : base(dataProtectionProvider.Create("ASP.NET Identity"))
{
TokenLifespan = TimeSpan.FromHours(6);
}
}
Everything else I kept the same. This solved the issue.

Related

ClaimsAuthenticationManager.Authenticate never gets called

I want to add some additional claims to a Principal during authentication. I am trying to implement a custom ClaimsAuthenticationManager in my MVC 4.5 project which uses Windows Authentication:
namespace Project.Infrastructure
{
public class ClaimsTransformer : ClaimsAuthenticationManager
{
public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
{
if (incomingPrincipal != null && incomingPrincipal.Identity.IsAuthenticated == true)
{
((ClaimsIdentity)incomingPrincipal.Identity).AddClaim(new Claim(ClaimTypes.Role, "Admin"));
}
return incomingPrincipal;
}
}
}
I have the web.config set up to use my custom class:
<configSections>
<section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
</configSections>
and
<system.identityModel>
<identityConfiguration>
<claimsAuthenticationManager type="Project.Infrastructure.ClaimsTransformer, [AssemblyName]" />
</identityConfiguration>
</system.identityModel>
But the Authenticate method never gets called. Am I missing something?
The missing step is that you need to add an HTTP Module to kick all of this off.
So, you need a class that looks like this:
public class MyClaimsAuthenticationModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.PostAuthenticateRequest += Context_PostAuthenticateRequest;
}
public void Dispose()
{
// Nothing to dispose, method required by IHttpModule
}
void Context_PostAuthenticateRequest(object sender, EventArgs e)
{
var transformer = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.ClaimsAuthenticationManager;
if (transformer != null)
{
var context = ((HttpApplication)sender).Context;
var principal = context.User as ClaimsPrincipal;
var transformedPrincipal = transformer.Authenticate(context.Request.RawUrl, principal);
context.User = transformedPrincipal;
Thread.CurrentPrincipal = transformedPrincipal;
}
}
}
This will pick up the transformer you specified in the web.config and call authenticate on it, then attach the returned principal to the HttpContext and the current thread.
You will also need something like the following in your web.config:
<system.webServer>
<modules>
<add name="MyClaimsAuthenticationModule" type="MyApplication.MyHttpModels.MyClaimsAuthenticationModule, MyApplicationAssembly" />
</modules>
</system.webServer>
Update
You can, of course, put the code from the method Context_PostAuthenticationRequest in the PostAuthenticateRequest handler in your Global.asax.cs class file. However, I prefer to keep the responsibilities of the classes small so I go for an implementation of IHttpModule so that the module does its thing and it is obvious what that is, and it is separate from other things that may be happening at various stages of the pipeline.
If your Global.asax.cs file is small then there is no problem with putting the code there. It should still work. However, you are mixing responsibilities in the class and it could get unwieldy in the future.
Are you calling the Authenticate method with something like this, and the Authentication is not taking place?
ClaimsTransformer manager = new ClaimsTransformer();
manager.Authenticate("resource", incomingPrincipal )
You may want to replace the "return incomingPrincipal" from inside the ClaimsTransformer class with a call to:
return base.Authenticate(resourceName, incomingPrincipal);
Also why do you need Windows Authentication?

Unity with interface that extends another interface

I have a class:
public class Foo : IFoo
{
}
and two interfaces:
Public interface IFoo : IBar<SomeType>
{
}
public interface IBar<T>
{
DoSomething(T t);
}
We are using XML Config,the code configuration works fine, but the web.config doesn't.
The error is like:
Resolution of the dependency failed, type = "IFoo", name = "(none)".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The current type, IBar`1[SomeType], is an interface and cannot be constructed. Are you missing a type mapping?
mlns="http://schemas.microsoft.com/practices/2010/unity">
<alias alias="IFoo"
type="IFoo, Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e4bf38905880b60b" />
<alias alias="Foo"
type="Foo, Something, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e4bf38905880b60b" />
<container name="SomeName">
<register type="IFoo" mapTo="Foo" />
</container>
</unity>
I believe you're probably using the default instance of the UnityContainer since you didn't mention anything about using a named instance of the container.
<container name="SomeName">
<register type="IFoo" mapTo="Foo" />
</container>
You're registering the mapping to "SomeName" instead of the default container.
Remove
name="SomeName"

StructureMap errors when using simple configuration based Constructor Injection

I have attempted a simple program to try out configuration based constructor injection. Here is the code:
using StructureMap;
namespace StructureMapConfig
{
class Program
{
static void Main(string[] args)
{
ObjectFactory.Initialize(x =>
{
x.PullConfigurationFromAppConfig = true;
});
var result = ObjectFactory.GetInstance<IIConstructor>();
}
}
public interface IIConstructor
{
}
public class Constructor : IIConstructor
{
public Constructor(bool test)
{
}
}
}
Here is my configuration file:
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="StructureMap"
type="StructureMap.Configuration.StructureMapConfigurationSection,StructureMap"/>
</configSections>
<StructureMap>
<DefaultInstance MementoStyle="Attribute"
PluginType="StructureMapConfig.IIConstructor,StructureMapConfig"
PluggedType="StructureMapConfig.Constructor,StructureMapConfig"
test="false"/>
</StructureMap>
<startup>
<supportedRuntime version="v4.0"
sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>
I keep getting a large stack trace when reading the config file, boiling down to this error:
Trying to visit parameter test of type System.Boolean in the
constructor for StructureMapConfig.Constructor, StructureMapConfig,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null --->
StructureMap.StructureMapException: StructureMap Exception Code: 205
Missing requested Instance property "test" for InstanceKey
"DefaultInstanceOfStructureMapConfig.IIConstructor,
StructureMapConfig, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null
The code definitely has a constructor argument called "test" and the destination type is correct - a boolean.
Can someone please give me guidance as to where I'm going wrong?
--
Note: I want to keep this in configuration only, as it will require a re-compile if this value is changed from "false" to "true", hence defeating the point of defining it in config.
Got it,
"MementoStyle" should be on the <StructureMap> element, not on the <DefaultInstance>

Castle Windsor Inversion of Control (IoC): using the Web.config to resolve dependencies

I was exploring the installer functionality of Castle Windsor based on the answers from a related question. I want to use the Web.config to specify the name of the database and I would rather not explicitly set the database name in my code. I tried Krzysztof Koźmic's example and when I debut the project my break-point at container.Register gets hit, but the dependency is still not resolved:
public class RepositoriesInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(AllTypes.FromThisAssembly()
.Where(Component.IsInSameNamespaceAs<SqlUsersRepository>())
.WithService.DefaultInterface()
.Configure(c => c.LifeStyle.Transient
.DependsOn(new { databaseName = "MyDatabaseName" })));
}
}
Sanders suggests that we can use the Web.config to resolve dependencies (note that he's doing this to get the connection string, but my connection string is encrypted so I'm doing in in a slightly different way):
<castle>
<components>
<component id="SqlUsersRepository"
service="MyDevArmyModel.Entities.IUsersRepository, MyDevArmyModel"
type="MyDevArmyModel.Entities.SqlUsersRepository, MyDevArmyModel">
<parameters>
<databaseName>MyDatabaseName</databaseName>
</parameters>
</component>
</components>
</castle>
My SqlUsersRepository and IUsersRepository are in the same namespace, but they're part of a class library which gets referenced in the current project. SqlUsersRepository looks up the connection string from the Web.Config the database name:
public interface IUsersRepository
{
IQueryable<User> Users { get; }
// ...
// and some other things
// ...
}
public class SqlUsersRepository : IUsersRepository
{
private DataContext dataContext;
private Table<User> usersTable;
public IQueryable<User> Users { get { return usersTable; } }
public SqlUsersRepository(string databaseName)
{
HttpRequestWrapper request = new HttpRequestWrapper(System.Web.HttpContext.Current.Request);
Configuration config = WebConfigurationManager.OpenWebConfiguration(request.ApplicationPath);
dataContext = new DataContext(config.GetConnetionString(databaseName));
usersTable = dataContext.GetTable<User>();
}
// .... the rest of the repository goes here
}
Any help on this?
P.S.
I'm still getting an exception, even if I use the hard-coded database name (as seen in the RepositoriesInstaller):
Server Error in '/' Application. Can't
create component
'MyProjectName.Controllers.UserController'
as it has dependencies to be
satisfied.
MyProjectName.Controllers.UserController
is waiting for the following
dependencies:
Services:
- MyProjectName.Entities.IUsersRepository
which was not registered. 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:
Castle.MicroKernel.Handlers.HandlerException:
Can't create component
'MyProjectName.Controllers.UserController'
as it has dependencies to be
satisfied.
MyProjectName.Controllers.UserController
is waiting for the following
dependencies:
Services:
- MyProjectName.Entities.IUsersRepository
which was not registered.
Update
I've posted an answer which addresses the exception problem, but I'm yet to figure out how to use the Web.config to store Castle Windsor specific sections.
You should be able to achieve this by reducing the XML to this:
<castle>
<components>
<component id="SqlUsersRepository">
<parameters>
<databaseName>MyDatabaseName</databaseName>
</parameters>
</component>
</components>
</castle>
and then make sure your registration registers the repository under the right key/id - e.g. like this:
container.Register(AllTypes(...).Configure(c => c.Named(c.Implementation.Name)))
where all keys will be set to the short name of each concrete type.
Please note that this naming scheme might not be appropriate for you, so you should probably adapt the c.Named(...) to whatever you deem right for your use case. Just make sure that the registration key for your repository matches that if the id attribute in the XML.
DependsOn the way you've done it = the parameter named "databaseName" has a component dependency with a key "MyDatabaseName".
You want to do a .Parameters(ForKey.Named("databasename").Value(ConfigurationManager.ConnectionStrings["MyDatabasename"].ConnectionString)).LifeStyle.Transient. ...
I figured out the dependency exception... the issue was that my repositories are in a different assembly, so I had to rig the installation a bit:
public class RepositoriesInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
foreach (AssemblyName name in Assembly.GetExecutingAssembly().GetReferencedAssemblies())
{
Assembly asm = Assembly.Load(name);
container.Register(AllTypes.FromAssemblyNamed(asm.FullName)
.Where(Component.IsInSameNamespaceAs<SqlUsersRepository>())
.WithService.DefaultInterface()
.Configure(c => c.LifeStyle.Transient
.DependsOn(new { databaseName = "MyDatabaseName" })));
}
container.Register(AllTypes.FromThisAssembly()
.Where(Component.IsInSameNamespaceAs<SqlUsersRepository>())
.WithService.DefaultInterface()
.Configure(c => c.LifeStyle.Transient
.DependsOn(new { databaseName = "MyDatabaseName" })));
}
}
Still trying to figure out how to get the database name from the castle section of the Web.config though.

Views in separate assemblies in ASP.NET MVC

I'm trying to create a webapplication where I want to be able to plug-in separate assemblies. I'm using MVC preview 4 combined with Unity for dependency injection, which I use to create the controllers from my plugin assemblies. I'm using WebForms (default aspx) as my view engine.
If I want to use a view, I'm stuck on the ones that are defined in the core project, because of the dynamic compiling of the ASPX part. I'm looking for a proper way to enclose ASPX files in a different assembly, without having to go through the whole deployment step. Am I missing something obvious? Or should I resort to creating my views programmatically?
Update: I changed the accepted answer. Even though Dale's answer is very thorough, I went for the solution with a different virtual path provider. It works like a charm, and takes only about 20 lines in code altogether I think.
It took me way too long to get this working properly from the various partial samples, so here's the full code needed to get views from a Views folder in a shared library structured the same as a regular Views folder but with everything set to build as embedded resources. It will only use the embedded file if the usual file does not exist.
The first line of Application_Start:
HostingEnvironment.RegisterVirtualPathProvider(new EmbeddedViewPathProvider());
The VirtualPathProvider
public class EmbeddedVirtualFile : VirtualFile
{
public EmbeddedVirtualFile(string virtualPath)
: base(virtualPath)
{
}
internal static string GetResourceName(string virtualPath)
{
if (!virtualPath.Contains("/Views/"))
{
return null;
}
var resourcename = virtualPath
.Substring(virtualPath.IndexOf("Views/"))
.Replace("Views/", "OrangeGuava.Common.Views.")
.Replace("/", ".");
return resourcename;
}
public override Stream Open()
{
Assembly assembly = Assembly.GetExecutingAssembly();
var resourcename = GetResourceName(this.VirtualPath);
return assembly.GetManifestResourceStream(resourcename);
}
}
public class EmbeddedViewPathProvider : VirtualPathProvider
{
private bool ResourceFileExists(string virtualPath)
{
Assembly assembly = Assembly.GetExecutingAssembly();
var resourcename = EmbeddedVirtualFile.GetResourceName(virtualPath);
var result = resourcename != null && assembly.GetManifestResourceNames().Contains(resourcename);
return result;
}
public override bool FileExists(string virtualPath)
{
return base.FileExists(virtualPath) || ResourceFileExists(virtualPath);
}
public override VirtualFile GetFile(string virtualPath)
{
if (!base.FileExists(virtualPath))
{
return new EmbeddedVirtualFile(virtualPath);
}
else
{
return base.GetFile(virtualPath);
}
}
}
The final step to get it working is that the root Web.Config must contain the right settings to parse strongly typed MVC views, as the one in the views folder won't be used:
<pages
validateRequest="false"
pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<controls>
<add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" />
</controls>
</pages>
A couple of additional steps are required to get it working with Mono. First, you need to implement GetDirectory, since all files in the views folder get loaded when the app starts rather than as needed:
public override VirtualDirectory GetDirectory(string virtualDir)
{
Log.LogInfo("GetDirectory - " + virtualDir);
var b = base.GetDirectory(virtualDir);
return new EmbeddedVirtualDirectory(virtualDir, b);
}
public class EmbeddedVirtualDirectory : VirtualDirectory
{
private VirtualDirectory FileDir { get; set; }
public EmbeddedVirtualDirectory(string virtualPath, VirtualDirectory filedir)
: base(virtualPath)
{
FileDir = filedir;
}
public override System.Collections.IEnumerable Children
{
get { return FileDir.Children; }
}
public override System.Collections.IEnumerable Directories
{
get { return FileDir.Directories; }
}
public override System.Collections.IEnumerable Files
{
get {
if (!VirtualPath.Contains("/Views/") || VirtualPath.EndsWith("/Views/"))
{
return FileDir.Files;
}
var fl = new List<VirtualFile>();
foreach (VirtualFile f in FileDir.Files)
{
fl.Add(f);
}
var resourcename = VirtualPath.Substring(VirtualPath.IndexOf("Views/"))
.Replace("Views/", "OrangeGuava.Common.Views.")
.Replace("/", ".");
Assembly assembly = Assembly.GetExecutingAssembly();
var rfl = assembly.GetManifestResourceNames()
.Where(s => s.StartsWith(resourcename))
.Select(s => VirtualPath + s.Replace(resourcename, ""))
.Select(s => new EmbeddedVirtualFile(s));
fl.AddRange(rfl);
return fl;
}
}
}
Finally, strongly typed views will almost but not quite work perfectly. Model will be treated as an untyped object, so to get strong typing back you need to start your shared views with something like
<% var Model2 = Model as IEnumerable<AppModel>; %>
Essentially this is the same issue as people had with WebForms and trying to compile their UserControl ASCX files into a DLL. I found this http://www.codeproject.com/KB/aspnet/ASP2UserControlLibrary.aspx that might work for you too.
protected void Application_Start()
{
WebFormViewEngine engine = new WebFormViewEngine();
engine.ViewLocationFormats = new[] { "~/bin/Views/{1}/{0}.aspx", "~/Views/Shared/{0}.aspx" };
engine.PartialViewLocationFormats = engine.ViewLocationFormats;
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(engine);
RegisterRoutes(RouteTable.Routes);
}
Set the 'Copy to output' property of your view to 'Copy always'
An addition to all you who are still looking for the holy grail: I've come a bit closer to finding it, if you're not too attached to the webforms viewengine.
I've recently tried out the Spark viewengine. Other than being totally awesome and I wouldn't go back to webforms even if I was threathened, it also provides some very nice hooks for modularity of an application. The example in their docs is using Windsor as an IoC container, but I can't imagine it to be a lot harder if you want to take another approach.

Categories