I am trying to implement a custom principal in an MVC5 app. To start I have tried to just implement IPrincipal and also override the base WebViewPage. However, the cast from to the customPrincipal is not working. I am getting :
Unable to cast object of type 'System.Security.Principal.WindowsPrincipal' to type
CustomPrincipal.
I cannot understand why this will not cast and want to make sure at least this works before I go down the path of implementing everything I need in the customPrincipal. Why is this unable to cast?
public abstract class CustomWebViewPage : WebViewPage
{
public virtual new CustomPrincipal User { get { return (CustomPrincipal)base.User; } }
}
public abstract class CustomWebViewPage<TModel> : WebViewPage<TModel>
{
public virtual new CustomPrincipal User { get { return (CustomPrincipal)base.User; } }
}
public class CustomPrincipal : IPrincipal
{
public bool IsInRole(string role)
{
throw new NotImplementedException();
}
public IIdentity Identity { get; private set; }
}
Related
PFB my code.
namespace ManualCSharpe
{
public class MyServices : Service
{
[Route("/L/hello/")] //RequestDTO one
public class HelloL
{
public string Name { get; set; }
}
[Route("/H/hello/")] //RequestDTO two
public class HelloH
{
public string Name1 { get; set; }
}
public class HelloResponse //ResponseDTO
{
public string Result { get; set; }
}
public class HelloServiceL : Service //Service One
{
public object Get(HelloL request)
{
return new HelloResponse { Result = "Low" };
}
}
public class HelloServiceH : Service //Service
{
public object Get(HelloH request)
{
return new HelloResponse { Result = "High" };
}
}
//Define the Web Services AppHost
public class AppHost : AppSelfHostBase
{
public AppHost()
: base("HttpListener Self-Host",new Assembly[] {typeof(HelloServiceL).Assembly, typeof(HelloServiceH).Assembly}) { }
public override void Configure(Funq.Container container) { }
}
//Run it!
static void Main(string[] args)
{
var listeningOn = args.Length == 0 ? "http://*:133/" : args[0];
var appHost = new AppHost()
.Init()
.Start(listeningOn);
Console.WriteLine("AppHost Created at {0}, listening on {1}",
DateTime.Now, listeningOn);
Console.ReadKey();
}
}
}
When I am tring to added two service then it is show below exception.
An unhandled exception of type 'System.Reflection.AmbiguousMatchException' occurred in ServiceStack.dll
Additional information: Could not register Request 'ManualCSharpe.MyServices+HelloL' with service 'ManualCSharpe.MyServices+HelloServiceL' as it has already been assigned to another service.
Each Request DTO can only be handled by 1 service.
I have below douts.
Here I have created two different DTO for Two Service. Why it is showing error like Each Request DTO can only be handled by 1 service. In simple word, Two route mapped with two DTO with two Service.
Can I create one route for multiple RequestDTO with multiple service? In Simple word, One Route/L/hello/ can be mapped with two DTO HelloL and HelloH.
You can't have Service class implementations nested inside another outer MyServices class:
public class MyServices : Service
{
[Route("/L/hello/")] //RequestDTO one
public class HelloL
{
public string Name { get; set; }
}
[Route("/H/hello/")] //RequestDTO two
public class HelloH
{
public string Name1 { get; set; }
}
public class HelloResponse //ResponseDTO
{
public string Result { get; set; }
}
public class HelloServiceL : Service //Service One
{
public object Get(HelloL request)
{
return new HelloResponse { Result = "Low" };
}
}
public class HelloServiceH : Service //Service
{
public object Get(HelloH request)
{
return new HelloResponse { Result = "High" };
}
}
}
Remove the outer MyServices class completely and just have the DTO's and Service classes directly under a C# namespace.
Also routes shouldn't end with a / suffix, so I'd change:
[Route("/L/hello/")]
to:
[Route("/L/hello")]
#mythz answer is correct for OP but I came here looking for an answer for a different situation which the cause was not particularly obvious - you will get this exception if you attempt to register the same assembly twice, for example, if you move a service implementation into the same assembly and were pulling it in like so:
public AppHost() : base("App", typeof(AdminService).GetAssembly(), typeof(InboundService).GetAssembly(),typeof(ProductService).GetAssembly())
For those of you who come here from a google search, a AmbiguousMatchException exception in ServiceStack can sometimes be triggered within ServiceStack but handled internally.
You can change your exception setting so it doesn't break on this exception.
I had changed my exception setting to break on all exceptions and this had me stuck for a while.
I am working in ASP.NET MVC 5 and I am using ASP.NET Identity. I have followed LukeP's solution here to get access to my ApplicationUser custom properties (e.g. User.DisplayUsername or User.DOB). Like Luke has suggested, I now have a custom IPrincipal implementation (basically exact same code as him).
This has a problem however, and I suspect it is do with with this line of code on the CustomPrincipal class:
public bool IsInRole(string role) { return false; }
I have a controller called ReviewController and on there I have this:
[Authorize(Roles = "Admin")]
public class ReviewController : Controller
{
// controller stuff
}
This isn't working. Even though the user I am logged in as is of role Admin. So I tried improving the code by doing this to the IsInRole method:
public class CustomPrincipal : ICustomPrincipal
{
public IIdentity Identity { get; private set; }
public bool IsInRole(string role)
{
var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(new BBContext()));
return roleManager.Roles.All(r => r.Name == role);
}
public CustomPrincipal(string email)
{
this.Identity = new GenericIdentity(email);
}
public string Id { get; set; }
public string DisplayUsername { get; set; }
public DateTime DOB { get; set; }
}
This has improved in the sense that I am now served the ReviewController. However it is still wrong because even user that are not in the Admin role are also allowed access. I know why that is too, but just don't know how to fix this.
How can I get it to work as it should?
I am trying to re-use the service registrations in an assembly that I use through a few services in my solution. I follow the example listed from the NServiceBus website to implement the solution. When following that, unless I add the IWantCustomInitialization interface, my Init method (and IoC container implementation) appears not to function. When I have that interface implemented, I get exceptions (listed in SO questions here and here). I can't seem to get it to work that there are no exceptions AND the dependencies in my MessageHandler are being populated properly. Here is my current EndpointConfig implementation.
[EndpointSLA("00:00:30")]
public class EndpointConfig : IConfigureThisEndpoint, AsA_Server, UsingTransport<Msmq>, INeedInitialization {
public void Init() {
Configure.With().ObjectBuilderAdapter();
}
}
public class ObjectBuilderAdapter : IContainer {
readonly IDependencyInjector injector;
public ObjectBuilderAdapter(IDependencyInjectionBuilder dependencyInjectionBuilder) {
injector = dependencyInjectionBuilder.Create(); //This method does all the common service registrations that I am trying to re-use
//injector.RegisterType<ExtractIncomingPrincipal, PrincipalExtractor>();
}
public void Dispose() {
injector.Dispose();
}
public object Build(Type typeToBuild) {
return injector.Resolve(typeToBuild);
}
public IContainer BuildChildContainer() {
return new ObjectBuilderAdapter(new DependencyInjectorBuilder());
}
public IEnumerable<object> BuildAll(Type typeToBuild) {
return injector.ResolveAll(typeToBuild);
}
public void Configure(Type component, DependencyLifecycle dependencyLifecycle) {
injector.RegisterType(component);
}
public void Configure<T>(Func<T> component, DependencyLifecycle dependencyLifecycle) {
injector.RegisterType(component);
}
public void ConfigureProperty(Type component, string property, object value) {
if (injector is AutofacDependencyInjector) {
((AutofacDependencyInjector)injector).ConfigureProperty(component, property, value);
} else {
Debug.WriteLine("Configuring {0} for property {1} but we don't handle this scenario.", component.Name, property);
}
}
public void RegisterSingleton(Type lookupType, object instance) {
injector.RegisterInstance(lookupType, instance);
}
public bool HasComponent(Type componentType) {
return injector.IsRegistered(componentType);
}
public void Release(object instance) { }
}
public static class Extensions {
public static Configure ObjectBuilderAdapter(this Configure config) {
ConfigureCommon.With(config, new ObjectBuilderAdapter(new DependencyInjectorBuilder()));
return config;
}
}
Note: When I use the INeedInitialization interface, I get the ComponentNotRegisteredException when it's looking for IStartableBus.
When you are trying to swap the built in container, then you need to implement IWantCustomInitialization in the same class that implements IConfigureThisEndpoint.
You can use your own container and register all your types in there and tell NSB to use that container.
For example:
public class EndpointConfig : IConfigureThisEndpoint, AsA_Server, IWantCustomInitialization
{
public void Init()
{
var container = new ContainerBuilder().Build();
Configure.With()
.AutofacBuilder(container);
}
}
I am trying to create a Custom Attribute for a ServiceStack Service with which I can control each method in the service Class.
This is the attribute class that I am implementing.
[AttributeUsage(AttributeTargets.Method|AttributeTargets.Class , Inherited = false, AllowMultiple = false)]
public class MyRequestFilterAttribute:RequestFilterAttribute
{
public string Provider { get; set; }
public MyRequestFilterAttribute(ApplyTo applyTo): base(applyTo)
{
this.Priority = (int) RequestFilterPriority.Authenticate;
}
public MyRequestFilterAttribute():this(ApplyTo.All)
{
}
public MyRequestFilterAttribute(ApplyTo applyTo, string provider): this(applyTo)
{
this.Provider = provider;
}
public MyRequestFilterAttribute(string provider): this(ApplyTo.All)
{
this.Provider = provider;
}
public override void Execute(IHttpRequest req, IHttpResponse res, object requestDto)
{}
}
This is the Service Class
[MyRequestFilter(ApplyTo.All)]
public class TodoService : RestServiceBase<Todo>
{
public TodoRepository Repository { get; set; }
public override object OnGet(Todo request)
{
if (request.Id == default(long))
return Repository.GetAll();
return Repository.GetById(request.Id);
}
public override object OnPost(Todo todo)
{
return Repository.Store(todo);
}
public override object OnPut(Todo todo)
{
return Repository.Store(todo);
}
[MyRequestFilter("Admin")]
public override object OnDelete(Todo request)
{
Repository.DeleteById(request.Id);
return null;
}
public object GetDetailsofALL()
{
return null;
}
}
I am able to get control on the Methods when I place the attribute on the Class level.
i.e
[MyRequestFilter(ApplyTo.All)]
public class TodoService : RestServiceBase<Todo>{}
What I require is to place an attribute on the method level as well and do some authentication such that only an admin has the right to perform this method of the service.
But when I place this attribute in the Delete method it is not working and the custom filter attribute is not getting hit. Only the class level attribute call works.
[MyRequestFilter("Admin")]
public override object OnDelete(Todo request){}
Is it possible to set the permission/filter attribute from the method level? If yes, how can I implement this?
No it's not possible to add it on the method. You can add it on the service class or the Request DTO and use the ApplyTo method filter to tell servicestack which methods it should apply to, e.g:
[MyRequestFilter(ApplyTo.All)]
[MyRequestFilter(ApplyTo.Delete, "Admin")]
public class TodoService : RestServiceBase<Todo> { ... }
You can also refer to the implementation of the [RequiredRole] and [RequestPermission] attributes for examples of Request Filter attributes that support this.
I am having a WCF application hosted on IIS.
I am initializing an IoC container in a custom ServiceHostFactory.
Basically what I would like is to be able to "inject" that IoC Container to each Service instance created within the scope of that ServiceHost.
How would you accomplish that?
Ariel
Like you said you will need a custom ServiceHostFactory that should be used in order to create your services. Something like this:
public class SessionPerCallServiceHostFactory : ServiceHostFactory
{
public SessionPerCallServiceHostFactory()
{
}
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
return new SessionPerCallServiceHost(serviceType, baseAddresses);
}
}
You will also need a ServiceHost responsible for creating the necessary service:
public class SessionPerCallServiceHost : ServiceHost
{
public SessionPerCallServiceHost()
{
}
public SessionPerCallServiceHost(Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
}
protected override void OnOpening()
{
Description.Behaviors.Add(new SessionPerCallServiceBehavior());
base.OnOpening();
}
}
With a custom implementation of IServiceBehavior that will be able to provider the InstanceProvider used to create the service instances:
public class SessionPerCallServiceBehavior : IServiceBehavior
{
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher cd = cdb as ChannelDispatcher;
if (cd != null)
{
foreach (EndpointDispatcher ed in cd.Endpoints)
{
ed.DispatchRuntime.InstanceProvider =
new SessionPerCallInstanceProvider(serviceDescription.ServiceType);
}
}
}
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection endpoints, BindingParameterCollection bindingParameters)
{
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
}
And finally the instance provider that will allow you to use the IoC to inject whatever you want in the requested service instance:
public class SessionPerCallInstanceProvider : IInstanceProvider
{
private readonly Type _serviceType;
public SessionPerCallInstanceProvider(Type serviceType)
{
_serviceType = serviceType;
}
public object GetInstance(InstanceContext instanceContext, System.ServiceModel.Channels.Message message)
{
//I'm creating it without any tricks but you could use your IoC container here
return Activator.CreateInstance(_serviceType);
}
public object GetInstance(InstanceContext instanceContext)
{
return GetInstance(instanceContext, null);
}
public void ReleaseInstance(System.ServiceModel.InstanceContext instanceContext, object instance)
{
}
}
Hope it helps!