How can you programatically add mappings to UnicastBusConfig? - c#

I would like to be able to add subscriptions to additional message types living on potentially different servers to my application at runtime. What I'm trying to achieve is a Monitoring application where I can add/remove subscriptions at runtime. Is this possible? How do I get a reference to the current UnicastBus mappings?
Here is what I'm doing so far, but I believe this will overwrite any mappings currently in existence.
MessageEndpointMappingCollection mappings = new MessageEndpointMappingCollection();
mappings.Add(new MessageEndpointMapping()
{
Messages = m.MessageType.ToString(),
Endpoint = m.QueueName
});
IComponentConfig<UnicastBusConfig> busConfig = config.Configurer.ConfigureComponent<UnicastBusConfig>(ComponentCallModelEnum.None);
busConfig.ConfigureProperty(u => u.MessageEndpointMappings, mappings);

Yves used this code in his Azure samples (to be found in NSB samples collection)
using NServiceBus.Config;
using NServiceBus.Config.ConfigurationSource;
namespace OrderService
{
class ConfigOverride : IProvideConfiguration<UnicastBusConfig>
{
public UnicastBusConfig GetConfiguration()
{
return new UnicastBusConfig
{
MessageEndpointMappings = new MessageEndpointMappingCollection
{
new MessageEndpointMapping { Messages="MyMessages", Endpoint="orderserviceinputqueue" }
}
};
}
}
}

The best way to approach this would be to implement IConfigurationSource and provide your own configuration. Then you could cherry pick what you would like to load from the config file (if anything) and what you would like to specify yourself at runtime.
I would reflect the DefaultConfigurationSource class or refer to this gist for guidance.

In a project, I am currently involved with, we are doing some content-based routing to dynamically subscribed/unsubscribed agents by keeping track of them in our own routing table.
We have wrapped the IBus in a decorator (by using Windsor's support of decorators, as described <plug>here</plug>), that sees if the message implements a special IRoutableMessage interface, that allows the decorator to route the message by explicitly specifying the destination endpoint via bus.Send(destinationEndpoint).
This was a little bit complex to get right, and I would recommend going with NServiceBus' built-in routing as far as possible. But is is possible to explicitly route messages to any endpoint.

If you are looking into monitoring, check out the NSBManager repository. This takes the opposite approach and lets the endpoints register with the manager.

Related

How to dynamically change OpenID configuration based on something in a single ASP.NET Core application?

We have some OpenID configuration specified in ConfigureServices in Startup.cs:
services.AddOpenIdConnect("something", "Something", options =>
{
// ... //
});
How can we change the configuration we've outlined here dynamically, on a per request basis, based on certain rules?
Can this be done in a middleware? If so, please give an example, thank you!
Don't think you can do that, but you can if you want add multiple services.AddOpenIdConnect(...) handlers and use a different one for different clients.
What kind of usecase do you have? What do you try to create?
There's nothing stopping you from adding the source of the OpenIdConnectHandler to your own application and then tweaking it to your needs. Its pretty simple and I have done that myself to learn the inner workings of it.
The source is here:
https://github.com/dotnet/aspnetcore/tree/master/src/Security/Authentication/OpenIdConnect
if (await _authenticationSchemeProvider.GetSchemeAsync(OpenIdConnectDefaults.AuthenticationScheme) == null)
_authenticationSchemeProvider.AddScheme(new AuthenticationScheme(OpenIdConnectDefaults.AuthenticationScheme, OpenIdConnectDefaults.AuthenticationScheme, typeof(OpenIdConnectHandler)));
var opendIDoption = new OpenIdConnectOptions();
OpenIDSSOConfiguration.SetupOIDOption(opendIDoption, openIDSSOConfiguration);
foreach(var postConfigure in _postConfigures)
{
postConfigure.PostConfigure(OpenIdConnectDefaults.AuthenticationScheme, opendIDoption);
}
_optionsCache.TryRemove(OpenIdConnectDefaults.AuthenticationScheme);
_optionsCache.TryAdd(OpenIdConnectDefaults.AuthenticationScheme, opendIDoption);
_postConfigureOptions.PostConfigure(OpenIdConnectDefaults.AuthenticationScheme, opendIDoption);
Here is my working solution of my.
serwices used are:
IEnumerable<IPostConfigureOptions<OpenIdConnectOptions>> postConfigures,
IPostConfigureOptions<OpenIdConnectOptions> postConfigureOptions,
IOptionsMonitorCache<OpenIdConnectOptions> optionsCache,
IAuthenticationSchemeProvider authenticationSchemeProvider)
Applying postConfigureOptions is crucial because OpenIdConnectHandler will throw exception that OpenIdConnectOptions is not correct configured.

Logging as a cross-cutting concern in WCF

I would like to log to file every time my Web service is called recording the name of the method called as well as the calling data.
To write in this file, I use Nlog but I would like not to make the logging call in each of my service operations. I'd prefer to automate this logging call somehow as a cross cutting concern.
Is it possible?
You can use a DI container supporting interceptors to log any WCF method call with input values. Here is an example for Ninject and old weird ASMX service (for WCF, idea is the same):
Let's consider the following client class:
public partial class LegacyClient : System.ServiceModel.ClientBase<Legacy>, Legacy
Because this class is partial, we may easily add to class the interface ILegacyClient containing methods we want to call. ReSharper extract the interface in a second. So place the partial class declaration in separate file:
public partial class LegacyClient : ILegacyClient {}
In DI config, add the interceptor:
Kernel.Bind(typeof(ILegacyClient))
.To<LegacyClient>()
.InRequestScope() //carefully choose a scope
.Intercept()
.With<LogRequestInterceptor>();
LogRequestInterceptor is the most interesting part:
using Ninject;
using Ninject.Extensions.Interception;
public class LogRequestInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
MethodInfo method = invocation.Request.Method;
var parameters = method.GetParameters();
var builder = new StringBuilder();
for (int index = 0; index < parameters.Length; index++)
{
object argument = invocation.Request.Arguments[index];
ParameterInfo parameterInfo = parameters[index];
if (!parameterInfo.IsOut)
{
//use any serialization you like
string text = $"{parameterInfo.Name} = {argument.ToJson()}, ";
builder.Append(text);
}
}
string joinedParameters = builder.ToString();
YourLogging(method.Name, joinedParameters);
//LegacyClient method call, don't forget this line
invocation.Proceed();
}
}
Last part to make things work. Create proxy object via DI and use it:
ILegacyClient client = Kernel.GetService<ILegacyClient>();
client.AnyMethodCall(...);
Direct creation is only an example, of course you may use constuctor or property injection instead and replace client interface with factory if you need.
Hope it helps!
You can try to use either Aspect Oriented programming (AOP) using Windsor Castle, PostSharp or other 3rd party Libraries offering AOP. Also, you may use interceptors from these Libraries.
WCF Extension might be another place to do this kind of logging.
Using WCF tracing. You can view the Service calls, message level details etc by enabling WCF tracing by Configuration.
The answer from Agalo is correct but too general, so I would just add a link to how to implement #2. I guess this is exactly what question author wants to have.
In a nutshell, you can implement your own parameter inspector (IParameterInspector) and inject it using service behavior (IServiceBehavior). Here you can find complete example how to do that for logging.

ServiceStack multiple implementations of same interface in Funq.Container

In ServiceStack application, I have Funq configured to inject a session per request like this:
container.Register<NHibernate.ISessionFactory>(sessionFactoryForDB1);
container.Register<NHibernate.ISession>(c => c.Resolve<NHibernate.ISessionFactory>()
.OpenSession())
.ReusedWithin(Funq.ReuseScope.Request);
My service looks like this, and it works just fine:
public class MyNhAwareService : Service
{
public ISession Session { get; set; }
public object Any(DoSomething request)
{
...
}
}
Now, the problem comes in when I want to add a second NHibernate database into the mix with its own session factory:
container.Register<NHibernate.ISessionFactory>(sessionFactoryForDB1);
container.Register<NHibernate.ISession>(c => c.Resolve<NHibernate.ISessionFactory>()
.OpenSession())
.ReusedWithin(Funq.ReuseScope.Request);
// add a different session factory
container.Register<NHibernate.ISessionFactory>(sessionFactoryForDB2);
I've been experimenting with a variety of ways Funq can be used, and I thought I had found the way forward when I discovered the 'RegisterNamed()" method, but that still doesn't help, as I can't use anything except TryResolve() from within my service.
This seems like it should be possible, but I'm beating my head against the wall trying to work it out...Any advice would be greatly appreciated.
You have a couple ways of going about this.
Option 1: Unique Interfaces
This option is to create a distinct interface for each NHibernate database so that they can be uniquely resolved by Funq.
For example:
interface FactoryA : NHibernate.ISessionFactory
{
}
interface FactoryB : NHibernate.ISessionFactory
{
}
You could then proceed as you are now. The same applies for the session. See here for a little more detail about the process:
How to register multiple IDbConnectionFactory instances using Funq in ServiceStack.net
Option 2: Named Instance
This option I am less familiar with, but you can name your instances using Funq:
container.Register<NHibernate.ISessionFactory>("FactoryA",sessionFactoryForDB1);
And then in your service, resolve it thusly:
ServiceStackHost.Instance.Container.ResolveNamed<NHibernate.ISessionFactory>("FactoryA");
This option uses Service Location, which I personally find less attractive.

ODataClient MaxProtocolVersion V3

I am trying to consume OData from a windows forms. So, what i have done to now is create a new project, i added a web service reference to the OData service and try to consume it.
My code is:
var VistaEntities = new VrExternalEntities("serviceURI");
var query = VistaEntities.VRtblCinemaType
.Where(
x =>
x.VRtblCinema_Operators
.Any
(
z =>
z.VRtblSessions
.Any
(
y =>
y.Session_dtmDate_Time > DateTime.Now
)
)
)
.Select
(
x =>
new
{
x.CinType_strCode,
x.CinType_strDescription
}
);
If i remove the Where clause it works. If i do it says that Any is not supported. I know i have to set MaxProtocolVersion to V3 but i do not know how to do it. I don't have an entity context or anything else. I only have what i have stated above.
Please provide steps on how to accomplish that.
Thanks in advance.
Giannis
You must retrieve the configuration of your DataService and set the MaxProtocolVersion of its behavior to V3.
The best place to do this is certainly in the InitializeService static method you can define in your service class, which will be given the proper configuration object as its config parameter by the environment. It will only be invoked once, typically at the first request.
Note #1: You need WCF Data Services 5.0 or greater. The best way to get it is probably via the Server NuGet package.
Note #2: Oddly enough, the DataServiceProtocolVersion type, although in the Common namespace, is included in the Client assembly (Microsoft.Data.Services.Client, provided by the Client NuGet package). I suggested a better organization here.
public class Vista : DataService<VistaContext>
{
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule(...);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
...
}
}
Update:
The client may indeed specify the desired version in the requests by using the DataServiceVersion HTTP header. It's currently recommended that you specify and support a range of versions using the MinDataServiceVersion and MaxDataServiceVersion headers if you can, for obvious reasons. Note however that the MinDataServiceVersion will be removed in OData 4.0 (see appendix E.1 of part 1 and "What's new" documents drafts).
The relevant documentation for the WCF Data Services 5.x implementation is available here. The documentation specific to the client seems pretty scarce, but looking at the reference you can see that you must use this constructor for the DataServiceContext to specify the maximum protocol version, and it looks like you cannot change it at any one point for subsequent requests without rebuilding a new context. You may attempt to fiddle with the headers directly, but I wouldn't expect it to work reliably (or at all).
So, to answer your question, you really need control over how you create the context for the client.

Proper use of [Import] attribute in MEF

I'm learning MEF and I wanted to create a simple example (application) to see how it works in action. Thus I thought of a simple translator. I created a solution with four projects (DLL files):
Contracts
Web
BingTranslator
GoogleTranslator
Contracts contains the ITranslate interface. As the name applies, it would only contain contracts (interfaces), thus exporters and importers can use it.
public interface ITranslator
{
string Translate(string text);
}
BingTranslator and GoogleTranslator are both exporters of this contract. They both implement this contract and provide (export) different translation services (one from Bing, another from Google).
[Export(typeof(ITranslator))]
public class GoogleTranslator: ITranslator
{
public string Translate(string text)
{
// Here, I would connect to Google translate and do the work.
return "Translated by Google Translator";
}
}
and the BingTranslator is:
[Export(typeof(ITranslator))]
public class BingTranslator : ITranslator
{
public string Translate(string text)
{
return "Translated by Bing";
}
}
Now, in my Web project, I simply want to get the text from the user, translate it with one of those translators (Bing and Google), and return the result back to the user. Thus in my Web application, I'm dependent upon a translator. Therefore, I've created a controller this way:
public class GeneralController : Controller
{
[Import]
public ITranslator Translator { get; set; }
public JsonResult Translate(string text)
{
return Json(new
{
source = text,
translation = Translator.Translate(text)
});
}
}
and the last piece of the puzzle should be to glue these components (parts) together (to compose the overall song from smaller pieces). So, in Application_Start of the Web project, I have:
var parts = new AggregateCatalog
(
new DirectoryCatalog(Server.MapPath("/parts")),
new DirectoryCatalog(Server.MapPath("/bin"))
);
var composer = new CompositionContainer(parts);
composer.ComposeParts();
in which /parts is the folder where I drop GoogleTranslator.dll and BingTranslator.dll files (exporters are located in these files), and in the /bin folder
I simply have my Web.dll file which contains importer. However, my problem is that, MEF doesn't populate Translator property of the GeneralController with the required translator. I read almost every question related to MEF on this site, but I couldn't figure out what's wrong with my example. Can anyone please tell me what I've missed here?
OK what you need to do is (without prescribing for performance, this is just to see it working)
public class GeneralController : Controller
{
[Import]
public ITranslator Translator { get; set; }
public JsonResult Translate(string text)
{
var container = new CompositionContainer(
new DirectoryCatalog(Path.Combine(HttpRuntime.BinDirectory, "Plugins")));
CompositionBatch compositionBatch = new CompositionBatch();
compositionBatch.AddPart(this);
Container.Compose(compositionBatch);
return Json(new
{
source = text,
translation = Translator.Translate(text)
});
}
}
I am no expert in MEF, and to be frank for what I use it for, it does not do much for me since I only use it to load DLLs and then I have an entry point to dependency inject and from then on I use DI containers and not MEF.
MEF is imperative - as far as I have seen. In your case, you need to pro-actively compose what you need to be MEFed, i.e. your controller. So your controller factory need to compose your controller instance.
Since I rarely use MEFed components in my MVC app, I have a filter for those actions requiring MEF (instead of MEFing all my controllers in my controller facrory):
public class InitialisePluginsAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
CompositionBatch compositionBatch = new CompositionBatch();
compositionBatch.AddPart(filterContext.Controller);
UniversalCompositionContainer.Current.Container.Compose(
compositionBatch);
base.OnActionExecuting(filterContext);
}
}
Here UniversalCompositionContainer.Current.Container is a singleton container initialised with my directory catalogs.
My personal view on MEF
MEF, while not a DI framework, it does a lot of that. As such, there is a big overlap with DI and if you already use DI framework, they are bound to collide.
MEF is powerful in loading DLLs in runtime especially when you have WPF app where you might be loading/unloading plugins and expect everything else to work as it was, adding/removing features.
For a web app, this does not make a lot of sense, since you are really not supposed to drop a DLL in a working web application. Hence, its uses are very limited.
I am going to write a post on plugins in ASP.NET MVC and will update this post with a link.
MEF will only populate imports on the objects which it constructs itself. In the case of ASP.NET MVC, it is ASP.NET which creates the controller objects. It will not recognize the [Import] attribute, so that's why you see that the dependency is missing.
To make MEF construct the controllers, you have to do the following:
Mark the controller class itself with [Export].
Implement a IDependencyResolver implementation which wraps the MEF container. You can implement GetService by asking the MEF container for a matching export. You can generate a MEF contract string from the requested type with AttributedModelServices.GetContractName.
Register that resolver by calling DependencyResolver.SetResolver in Application_Start.
You probably also need to mark most of your exported parts with [PartCreationPolicy(CreationPolicy.NonShared)] to prevent the same instance from being reused in several requests concurrently. Any state kept in your MEF parts would be subject to race conditions otherwise.
edit: this blog post has a good example of the whole procedure.
edit2: there may be another problem. The MEF container will hold references to any IDisposable object it creates, so that it can dispose those objects when the container itself is disposed. However, this is not appropriate for objects with a "per request" lifetime! You will effectively have a memory leak for any services which implement IDisposable.
It is probably easier to just use an alternative like AutoFac, which has a NuGet package for ASP.NET MVC integration and which has support for per-request lifetimes.
As #Aliostad mentioned, you do need to have the composition initialise code running during/after controller creation for it to work - simply having it in the global.asax file will not work.
However, you will also need to use [ImportMany] instead of just [Import], since in your example you could be working with any number of ITranslator implementations from the binaries that you discover. The point being that if you have many ITranslator, but are importing them into a single instance, you will likely get an exception from MEF since it won't know which implementation you actually want.
So instead you use:
[ImportMany]
public IEnumerable<ITranslator> Translator { get; set; }
Quick example:
http://dotnetbyexample.blogspot.co.uk/2010/04/very-basic-mef-sample-using-importmany.html

Categories

Resources