How to implement an Access Control Handler in NServiceBus - c#

Just wanted to know , if there is a way to implement an Access control Message handler in NServiceBus.By 'Access Control Handler' i mean One handler should always execute before other handlers and should control (or rather prevent conditionally the execution of the other handler).
Does someone know how to implement this in NServiceBus?
I have specified the Priority of the handlers to get executed in the EndPointConfig as this
public class EndpointConfig : IConfigureThisEndpoint, AsA_Server, ISpecifyMessageHandlerOrdering
{
#region ISpecifyMessageHandlerOrdering Members
public void SpecifyOrder(Order order)
{
order.Specify<First<AccessControlHandler>>();
}
#endregion
}
Thanks in advance,
Vijay.

You can by creating your AccessControlHandler like the following
public class AccessControlHandler : IHandleMessages<IMessage>
{
public IBus Bus { get; set; }
public void Handle(IMessage message)
{
IDictionary<string, string> headers = Bus.CurrentMessageContext.Headers;
string token;
if (headers.TryGetValue("access_token", out token))
{
if (token == "MY_SECRET")
{
Console.WriteLine("User authenticated");
return;
}
}
Console.WriteLine("User not authenticated");
Bus.DoNotContinueDispatchingCurrentMessageToHandlers();
}
The last line is an important one as this tells the bus the message has succeeded but does not pass the message further down the pipeline

Related

Simple Injector is missing one of the open generic types after it is registered - what might be happening?

I'm having some difficulty with registering some open generic types with simple injector.
In startup I am registering in the following way..
var assemblies = LoadAssemblies("MyProjectName");
_container.Register(typeof(IMessageProcessor<>), assemblies, Lifestyle.Singleton);
When I try to get an instance one of them is missing. If I try to explicitly register the instance I get an error that it is already registered so i'm a bit lost as to what is happening.
I have checked the classes and they all look the same and exist in the same assembly.
The interfaces look like...
public interface IBaseMessageProcessor
{
Task Process<T>(T message);
}
public interface IMessageProcessor<T> : IBaseMessageProcessor where T : BaseMessage
{
Task Process(T message);
}
There are multiple examples that implement these interfaces that look like..
public interface IAssignToMultipleMessageProcessor : IMessageProcessor<AssignToMultipleMessage> { }
public interface IReturnBenefitMessageProcessor : IMessageProcessor<ReturnBenefitMessage> { }
public interface IAssignWelcomeBenefitsMessageProcessor : IMessageProcessor<AssignWelcomeBenefitsMessage> { }
In total there are six like IMessageProcessor<> where the Messages all inherit from BaseMessage
The concerete example of the above three look like this..
public class AssignToMultipleMessageProcessor : IAssignToMultipleMessageProcessor
{
public async Task Process(AssignToMultipleMessage message)
{
await Task.CompletedTask;
}
public async Task Process<T>(T message)
{
if (message is AssignToMultipleMessage assignToMultipleMessage)
{
await Process(assignToMultipleMessage);
}
}
}
public class ReturnBenefitMessageProcessor : IReturnBenefitMessageProcessor
{
public async Task Process(ReturnBenefitMessage message)
{
await Task.CompletedTask;
}
public async Task Process<T>(T message)
{
if (message is ReturnBenefitMessage assignToMultipleMessage)
{
await Process(assignToMultipleMessage);
}
}
}
public class AssignWelcomeBenefitMessageProcessor : IAssignWelcomeBenefitsMessageProcessor
{
public async Task Process(AssignWelcomeBenefitsMessage message)
{
await Task.CompletedTask;
}
public async Task Process<T>(T message)
{
if (message is AssignWelcomeBenefitsMessage assignWelcomeBenefitsMessage)
{
await Process(assignWelcomeBenefitsMessage);
}
}
}
When I debug the startup the container shows all six instances are in the LifeStyleRegistrationCache of the container as Singletons.
Later when trying to get the instance...
var instance = scope.GetInstance<IAssignWelcomeBenefitsMessageProcessor>();
All six are still present in the LifeStyleResistrationCache as Singletons but the error is thrown
No registration for type IAssignWelcomeBenefitsMessageProcessor could be found.
In the LifeStyleRegistrationCache it shows {[{Name = AssignWelcomeBenefitMessageProcessor FullName = MyAppName.MessageProcessing.AssignWelcomeBenefitMessageProcessor}, {System.WeakReference}]}
The SerializationStackTraceString says...
at SimpleInjector.Container.ThrowMissingInstanceProducerException(Type type)\r\n at SimpleInjector.Container.GetInstanceFromProducer(InstanceProducer instanceProducer, Type serviceType)\r\n at SimpleInjector.Container.GetInstanceForRootType(Type serviceType)\r\n at SimpleInjector.Container.GetInstance(Type serviceType)\r\n at SimpleInjector.Scope.GetInstance(Type serviceType)\r\n at SimpleInjector.Scope.GetInstance[TService]()\r\n
All the other five instances can be successfully resolved in the same way but this one is failing. Would really appreciate some help on this if anyone can point me in the right direction.
Cheers :)

Provide user information from signalr request in business logic layer using autofac

I have an ASP.NET MVC 5 Application with a SignalR 2 hub and using autofac for the DI.
The entire business logic is encapsulated in manager classes in their own layer. Some manager methods need informations about the current logged in user (UserId, TenantId, ..).
I solved this problem by injecting an AuthorizationProvider into each manager class that needs the user information.
public interface IAuthorizationProvider
{
long? GetUserId();
long? GteTenantId();
}
public class MyManager : IMyManager
{
private IAuthorizationProvider _authorizationProvider;
public MyManager(IAuthorizationProvider authorizationProvider)
{
_authorizationProvider = authorizationProvider;
}
public void MyMethod()
{
// Getting the User information here is pretty simple
long userId = _authorizationProvider.GetUserId();
}
}
Normally I can get the user information from the HttpContext and from the session. So I wrote a SessionAuthorizationProvider:
public class SessionAuthorizationProvider{
public long? GetUserId()
{
HttpContext.Current?.Session?[SessionKeys.User]?.Id;
}
public long? GteTenantId() { ... }
}
But now I have a new method in the SignalR hub that use the same mechanism.
[HubName("myHub")]
public class MyHub : Hub
{
private IMyManager _myManager;
public MyHub(IMyManager myManager)
{
_myManager = myManager;
}
[HubMethodName("myHubMethod")]
public void MyHubMethod(long userId, long tenantId)
{
_myManager.MyMethod();
}
}
The problem is that a SignalR request doesn't have a session. Therefore I have also set the required user information in the hub method as parameters postet from the client.
So I thought it is the best solution for this problem to write a new AuthorizationProvider for SignalR and adapt the depdendency resolver. But I can't get the current user in the new SignalrAuthorizationProvider.
public class SignalrAuthorizationProvider{
public long? GetUserId()
{
// How to get the user information here???
}
public long? GteTenantId() { /* and here??? */ }
}
Is there a recommended solution to this problem?
Of course, I can extend MyMethod to accept the user information as a parameter. But MyMethod calls another method from another manager and that manager also calls another method. The user information is only needed for the last method call. So I had to change at least 3 methods and many more in the future.
Here is a sketch of the problem
This is a potential solution. But it's very bad
Session is not supported by SignalR by default and you should avoid using it. See No access to the Session information through SignalR Hub. Is my design is wrong?. But you still can use cookie or querystring to get the desired value.
In both case you need to have access to the HubCallerContext of the underlying hub, the one that is accessible through the Context property of the Hub.
In a ideal word you should just have to had the dependency to the SignalAuthorizationProvider
ie :
public class SignalrAuthorizationProvider {
public SignalrAuthorizationProvider(HubCallerContext context){
this._context = context;
}
private readonly HubCallerContext _context;
public long? GetUserId() {
return this._context.Request.QueryString["UserId"]
}
}
But due to SignalR design it is not possible. Context property is assigned after construction of the Hub and AFAIK there is no way to change it.
Source code here : HubDispatcher.cs
One possible solution would be to inject a mutable dependency inside the Hub and alter the object in the OnConnected, OnReconnected methods.
public class SignalrAuthorizationProvider : IAuthorizationProvider
{
private Boolean _isInitialized;
private String _userId;
public String UserId
{
get
{
if (!_isInitialized)
{
throw new Exception("SignalR hack not initialized");
}
return this._userId;
}
}
public void OnConnected(HubCallerContext context)
{
this.Initialize(context);
}
public void OnReconnected(HubCallerContext context)
{
this.Initialize(context);
}
private void Initialize(HubCallerContext context) {
this._userId = context.QueryString["UserId"];
this._isInitialized = true;
}
}
and the Hub
public abstract class CustomHub : Hub
{
public CustomHub(IAuthorizationProvider authorizationProvider)
{
this._authorizationProvider = authorizationProvider;
}
private readonly IAuthorizationProvider _authorizationProvider;
public override Task OnConnected()
{
this._authorizationProvider.OnConnected(this.Context);
return base.OnConnected();
}
public override Task OnReconnected()
{
this._authorizationProvider.OnReconnected(this.Context);
return base.OnReconnected();
}
}
Having a mutable dependency is not the best design but I can't see any other way to have access to IRequest or HubCallerContext.
Instead of having an abstract Hub class which is not a perfect solution. You can change the RegisterHubs autofac method to use AOP with Castle.Core and let the interceptor calls the methods for you.

No error messages with Fluent Validation in ServiceStack

I am just starting to familiarise myself with ServiceStack and have come upon FluentValidation. I have followed the introductions and created a small Hello App.
My problem is that when I try to validate the request DTO no error messages are returned to describe how it failed validation, only a blank Json object {}.
Myself, I think the validation is autowired to the DTO so there should be no need for me to write any extra code.
The answer is probably blatant but I cannot see it. Any help would be greatly appreciated. My code is below:
namespace SampleHello2
{
[Route("/hello")]
[Route("/hello/{Name}")]
public class Hello
{
public string Name { get; set; }
}
public class HelloResponse
{
public string Result { get; set; }
}
public class HelloService : Service
{
public object Any(Hello request)
{
return new HelloResponse { Result = "Hello, " + request.Name };
}
}
public class HelloValidator : AbstractValidator<Hello>
{
public HelloValidator()
{
//Validation rules for all requests
RuleFor(r => r.Name).NotNull().NotEmpty().Equal("Ian").WithErrorCode("ShouldNotBeEmpty");
RuleFor(r => r.Name.Length).GreaterThan(2);
}
}
public class Global : System.Web.HttpApplication
{
public class HelloAppHost : AppHostBase
{
//Tell Service Stack the name of your application and where to find your web services
public HelloAppHost() : base("Hello Web Services", typeof(HelloService).Assembly) { }
public override void Configure(Funq.Container container)
{
//Enable the validation feature
Plugins.Add(new ValidationFeature());
container.RegisterValidators(typeof(HelloValidator).Assembly);
//register any dependencies your services use, e.g:
// container.Register<ICacheClient>(new MemoryCacheClient());
}
}
//Initialize your application singleton
protected void Application_Start(object sender, EventArgs e)
{
new HelloAppHost().Init();
}
}
}
P.S. Really enjoying using ServiceStack, It really is a fantastic project so thanks.
Edit
So for example:
Calling: http://localhost:60063/hello/Ian?format=json returns {"Result":"Hello, Ian"}.
Whereas Calling: http://localhost:60063/hello/I?format=json returns {}.
The second call returns {} where I was expecting auto generated error messages.
I found the answer. It was an overlook on my behalf:
This was in the documentation and I overlooked it:
All Error handling and validation options described below are treated
in the same way - serialized into the ResponseStatus property of your
Response DTO making it possible for your clients applications to
generically treat all Web Service Errors in the same way.
So all that was missing from my code was to add the following line into the HelloResponse class.
public ResponseStatus ResponseStatus { get; set; }

Validate WCF user based on URL

If I have a wcf rest service such as http://somedomain.com/service.svc/uniqueid/somemethod/parameter1
then is there a way to globally check if the uniqueid is valid for every request hitting the server.
I could put in a check for every operation contract but I'm looking for a way where this is not needed so that everytime the service is accessed the uniqueid is checked and does not proceed if invalid.
Just for some further background as to what I'm trying to achieve... The WCF service is an open API. Getting a uniqueid is also open and requires no kind of signup. I want to use the uniqueid so if the API is abused I can easily pull 1 ID's access without affecting any of the other users of the system.
UPDATE:Based on Mike's Suggestion I've created an IParameterInspector
[AttributeUsage(AttributeTargets.Class)]
class IDParameterInspector : Attribute, IParameterInspector
And attached it to my Service class
[IDParameterInspector]
public class MetaData : IMetaData
The problem I now have is the ApplyDispatchBehavior never runs.
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
{
if (channelDispatcher == null)
{
continue;
}
foreach (var endPoint in channelDispatcher.Endpoints)
{
if (endPoint == null)
{
continue;
}
foreach (var operation in endPoint.DispatchRuntime.Operations)
{
operation.ParameterInspectors.Add(this);
}
}
}
}
Does anyone now what I'm doing wrong?
This is how to use a parameter inspector and custom behaviour via attributes. You need to unfortunately implement both.
So starting with the decoration of the service method in the interface
[MyFirstCustomBehavior()]
string SayHello(string language);
We then need to define the MyFirstCustomBehavior class.
internal sealed class MyFirstCustomBehavior : Attribute, System.ServiceModel.Description.IOperationBehavior
{
#region IOperationBehavior Members
public void AddBindingParameters(System.ServiceModel.Description.OperationDescription operationDescription, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
//no special behaviour
}
public void ApplyClientBehavior(System.ServiceModel.Description.OperationDescription operationDescription, System.ServiceModel.Dispatcher.ClientOperation clientOperation)
{
throw new NotImplementedException();
}
public void ApplyDispatchBehavior(System.ServiceModel.Description.OperationDescription operationDescription, System.ServiceModel.Dispatcher.DispatchOperation dispatchOperation)
{
dispatchOperation.ParameterInspectors.Add(new MyFirstCustomParameterInspector());
}
public void Validate(System.ServiceModel.Description.OperationDescription operationDescription)
{
//no special behaviour
}
#endregion
}
We then need to code up the inspector.
internal sealed class MyFirstCustomParameterInspector : System.ServiceModel.Dispatcher.IParameterInspector
{
#region IParameterInspector Members
public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
{
////do stuff here
}
public object BeforeCall(string operationName, object[] inputs)
{
////or here
return null;
}
#endregion
}
You should then be good to go.
You can try creating a custom service behavior that will affect all the incoming requests.
Here is an example that filters the requests based upon IP address and you can use that as a reference. If I get some time I'll post some code.

Synchronized message passing with Prism

In our prism application we need to load a module to the centre pane when the user clicks an item in a tree(seperate module). The module in the centre pane(say designer module) can open a file and display itself if it is given a path. How can I pass the path of the file to this module?
For example
in Designer module
public DesignerViewModel(DataAccess dataAccess)// This will be injected
{
}
//The following class can create the model objects using the IDataService for getting data from remote location
public DataAccess(IDataService service)//this will be injected
{
}
The data access object is local to the Designer module, so I wouldnt like to expose it to outside the module. So the registration is done in the module
public class DesignerModule : IModule
{
public void Initialize()
{
var container = ServiceLocator.Current.GetInstance<IUnityContainer>();
container.RegisterType<Object, DesignerView>("DesignerUI");
container.RegisterType<DataAccess>();
}
}
IDataService is registered in the application level
public class BootStrapper : UnityBootstrapper
{
protected override void ConfigureContainer()
{
base.ConfigureContainer();
Container.RegisterType<IDataService, DataService>();
}
}
Note that IDataService is a singleton for the entire app. I cannot pass the path of file which is specific to a module instance in IDataService. Note that you can open any number of modules in the centre pane as you like, just click on a tree item->tree will fire an event with the selected item id->app will find out a path corresponding to the item id and invoke the module.
How will I pass the path when I say _regionManager.AddToRegion("CenterRegion", DesignerModule); Prism will do all the dependency injections beautifully, but how to pass the path is a big question?
You can use EventAggregator to exchange with messages beetwen modules.
Each module subscribe to EventAggregator.
While you open a module you can send to host control notification about newborn.
Host control send response back with initialization data.
public class MessageEvent : CompositePresentationEvent<Message>{}
internal class MessageReceiver
{
private readonly MessageEvent _evt;
private readonly string _myId = Guid.NewGuid().ToString();
internal MessageReceiver(IEventAggregator eventAggregator)
{
_evt = eventAggregator.GetEvent<MessageEvent>();
_evt.Subscribe(Receive, true);
_evt.Publish(new Message { Source = _myId, Command = Message.Commands.WhoIAm });
}
public void Receive(Message message)
{
switch (message.Command)
{
case Message.Commands.WhoIAm:
_evt.Publish(
new Message
{
Destination = message.Source,
Command = Message.Commands.Initialize,
MessageData = Encoding.UTF8.GetBytes("init data")
});
break;
case Message.Commands.Initialize:
if (message.Destination == _myId)
{
//init
}
break;
}
}
}
public class Message
{
public enum Commands { Initialize, WhoIAm }
public string Source { get; set; }
public string Destination { get; set; }
public Commands Command { get; set; }
public byte[] MessageData { get; set; }
}
I found out the answer from my colleague.The parameters can be overriden with your own objects when you call Resolve(). So create the object which is going to be injected, populate it and pass with the Resolve<>() with ParameterOverride. Search for ParameterOverride in google for more information.

Categories