How can I let Rebus determine an endpoint for an interface and not for an implementation of that interface - rebus

When I Send an instance created by AutoMapper.Mapper.DynamicMap() I run into an error where Rebus seems to want to determine an endpoint for proxy type returned by DynamicMap. This instance will contain an implementation of T assuming T is an interface type.
Is there a way in which I can let Rebus determine an endpoint for the interface type T and not for the implementing type returned by DynamicMap()?
I tried playing around with IDetermineMessageOwnership but had no luck so far.
public static void Send<T>(this IBus bus, object source)
{
var message = Mapper.DynamicMap<T>(source);
bus.Send<T>(message);
}
Thanks in advance!

Sure! In your case, you could create your own implementation of IDetermineMessageOwnership which is the service that Rebus uses to map a message type to an endpoint.
If you want to leverage Rebus' existing logic, you could decorate any chosen strategy and extend it with a keep-looking-at-all-implemented-interfaces-until-one-can-be-mapped strategy like so:
Configure.With(adapter)
.(...)
.MessageOwnership(o => o.FromRebusConfigurationSection())
.Decorators(d => d.AddDecoration(DecorateOwnershipMapping)))
.CreateBus()
.Start();
where DecorateOwnershipMapping would install a decorator on top of whatever is configured like so:
void DecorateOwnershipMapping(ConfigurationBackbone b)
{
b.DetermineMessageOwnership = new CustomizedEndpointMapper(b.DetermineMessageOwnership);
}
and a possible implementation could look like this:
class CustomizedEndpointMapper : IDetermineMessageOwnership
{
readonly IDetermineMessageOwnership wrappedEndpointMapper;
public CustomizedEndpointMapper(IDetermineMessageOwnership wrappedEndpointMapper)
{
this.wrappedEndpointMapper = wrappedEndpointMapper;
}
public string GetEndpointFor(Type messageType)
{
var mappingCandidates = new[] {messageType}
.Concat(messageType.GetInterfaces())
.ToList();
foreach (var typeToTry in mappingCandidates)
{
try
{
return wrappedEndpointMapper.GetEndpointFor(typeToTry);
}
catch{}
}
throw new InvalidOperationException(string.Format("Could not determine the owner of message of type {0} - attempted to map the following types: {1}",
messageType, string.Join(", ", mappingCandidates)));
}
}
thus iterating through the concrete type as well as all inherited interface types when trying to determine the owning endpoint.
In your case, I believe this would work flawlessly when determining the message owner. Only problem is that the serializer will most likely complain, because the dynamically generated type cannot be recognized again when the message is received.
Hence, this trick requires customization of the serializer as well. If you're using the (default) JSON serializer, you might get away with some custom resolvers like so:
Configure.With(...)
.(...)
.Serialization(s => s.UseJsonSerializer()
.AddNameResolver(CustomNameResolver)
.AddTypeResolver(CustomTypeResolver))
.(...)
where CustomNameResolver and CustomTypeResolver are methods that must then take care of mapping the type to a type name and mapping the type name to a type that can then be deserialized into. In order to make this work with AutoMapper, you'll probably need to either
a) somehow use AutoMapper to look up the type of the received message and return that type from CustomTypeResolver, or
b) customize the serializer to have AutoMapper somehow participate in generating the object to be returned
but I must admit that I'm unsure whether the last part will play out smoothly.
A final note: if you succeed in making this work, I suggest you pack up your configuration spells into a reusable extension method on RebusConfigurer so that your endpoints can just go
Configure.With(...)
.(...)
.UseMyFunkyAutoMapperMessagesJustTheWayILikeIt()
.CreateBus().Start();
in all your Rebus endpoints...
I'll appreciate it if you'll let me know how this works out for you! :)

Related

ActivatorUtilities.CreateInstance giving "A suitable constructor not found" for simple examples

So I am building a complex case here with inheritance and IOC, need to use ActivatorUtilities to inject instances and pass parameters... no matter what I do I get the following error:
System.InvalidOperationException: 'A suitable constructor for type
'blabla.ISimpleTest' could not
be located. Ensure the type is concrete and all parameters of a public
constructor are either registered as services or passed as arguments.
Also ensure no extraneous arguments are provided.'
So in order to discard what could be the problem and ensure there is no constructor issues, I created a very very simple scenario that gives me the same error.
startup.cs
services.AddScoped<ISimpleTest, SimpleTest>();
the class and the interface, very simple here:
public interface ISimpleTest
{
}
public class SimpleTest : ISimpleTest
{
public SimpleTest()
{
}
}
test
var theInstance = ActivatorUtilities.CreateInstance<ISimpleTest>(ServiceProvider);
Additional notes
The ServiceProvider instance is fine (the rest/entire application depends on it).
Tried with and without adding the public constructor(empty params)
Tried also constructor with params, same error.
Tried to specify the params[] parameter, by sending null or empty array, same issue.
Extra test:
Just to confirm it's properly registered, I tried to get the instance using the Service provider, and works without issues:
//No issues this way:
var yyy = ServiceProvider.GetService<ISimpleTest>();
What am I doing here wrong? According to documentations, this should be enough to work

How can I parse ODataQueryOptions from a string?

I have to provide some read endpoints for our EF6 entities on an ASP.NET API that conform to the OData specification. Entity retrieval works well based upon functions that accept a System.Web.Http.OData.Query.ODataQueryOptions<TEntity> instance.
Now, according to the docs, that implementation of OData does not support $count.
We would, however, like to offer at least the capability to retrieve the total count of a (filtered) data set as shown in the docs, like (by slightly combining several of those samples):
http://host/service/Products/$count($filter=Price gt 5.00)
(Based on the spec, I understand that this should be a valid, specification-conformant OData query for the number of products whose price is greater than 5ยค. Please correct me if I'm wrong.)
Now, retrieving the count based on the IQueryable returned from ODataQuerySettings.ApplyTo is trivial. So is capturing requests to this route:
[Route("$count({queryOptions})")]
public int Count(ODataQueryOptions<ProductEntity> queryOptions)
The only bit that is missing is that the queryOptions portion of the route should be parsed into the ODataQueryOptions<ProductEntity> instance. On other OData endpoints, this works without any further ado. However, even when I call this endpoint with a $filter, all I am getting is an "empty" (i.e. initialized to default values) ODataQueryOptions<ProductEntity> instance with no filter set.
Alternatively, I can declare my web API endpoint like this:
[Route("$count({queryOptions})")]
public int Count(string rawQueryOptions)
Within this method, rawQueryOptions contains the query options that I wish to pass to OData, that is, parse to populate an ODataQueryOptions<ProductEntity> instance.
This must be very straightforward as the very same thing happens for any other OData endpoint. For a comparison:
[Route("")]
public IEnumerable<object> Filter(ODataQueryOptions<ProductEntity> queryOptions)
This works; the query options are populated as expected, unlike it is the case with my above endpoint.
How can I populate my OData query options instance based on the string extracted from my route?
Some more things I have tried:
Applied [FromUri] to the queryOptions parameter.
Applied [ODataQueryParameterBinding] to the queryOptions parameter.
Although the syntax is a little bit different to your request, the .Net OData Implementation has the support you need OOTB, if you're asking this question at all, that indicates that you are trying to add OData support to your standard API.
Given that you have EF6 already on an ASP.Net API... Why not just expose the OData controllers on another route? In this way you get the full implementation of query support without ever needing to parse the QueryOptions at all.
Updated
If adding new controllers in a separate route is not suitable you can easily upgrade your existing ApiControllers and Implement OData routes in place of the existing ones.
ODataController inherits from ApiController but includes some helper methods that simplify working with OData response conventions, so upgrading in place is generally non-breaking.
As an example, the following is the only controller code that is needed to allow all the supported OData Query Options to return data from an EF DbSet, this includes full support for $select, $expand, $filter, $apply and even $count across a nested $filter.
public partial class ResidentsController : ODataController
{
protected MyEF.Context db = new MyEF.Context();
[EnableQuery]
public async Task<IHttpActionResult> Get(ODataQueryOptions<MyEF.Resident> options)
{
return Ok(db.Residents);
}
}
The magic that allows this is not the ODataController itself, the EnableQueryAttribute parses/translates the QueryOptions and applies this to the Linq to Entities expression that is returned from the method.
The final component to make this work is to register the routes, this is a little bit more involved than standard API because you need to define the EdmModel first, but in doing so we never need to parse the incoming query parameters.
a minimal example to configure the model and routes for the above controller might look like this:
public static void Register(HttpConfiguration config)
{
var builder = new ODataConventionModelBuilder();
builder.EntitySet<Resident>("Residents");
IEdmModel model = builder.GetEdmModel();
// To enable $select and $filter on all fields by default
config.Count().Filter().OrderBy().Expand().Select().MaxTop(null);
// can also be configured like this
config.SetDefaultQuerySettings(new Microsoft.AspNet.OData.Query.DefaultQuerySettings()
{
EnableCount = true,
EnableExpand = true,
EnableFilter = true,
EnableOrderBy = true,
EnableSelect = true,
MaxTop = null
});
// Map the routes from the model using OData Conventions
config.MapODataServiceRoute("odata", "odata", model);
}
How to Configure the $count syntax you desire
although your expected syntax for count of filtered collections is not supported OOTB, the syntax that is supported is very close, so you could easily manipulate the query with a URL re-write module
Your expected syntax:
http://host/service/Products/$count($filter=Price gt 5.00)
.Net Supported syntax
http://host/service/Products/$count?$filter=Price gt 5.00
OwinMiddleware:
/// <summary>
/// Rewrite incoming OData requests that are implemented differently in the .Net pipeline
/// </summary>
public class ODataConventionUrlRewriter : OwinMiddleware
{
private static readonly PathString CountUrlSegments = PathString.FromUriComponent("/$count");
public ODataConventionUrlRewriter(OwinMiddleware next)
: base(next)
{
}
public override async Task Invoke(IOwinContext context)
{
// OData spec says this should work: http://host/service/Products/$count($filter=Price gt 5.00)
// But in .Net the filter needs to be in the query: http://host/service/Products/$count?$filter=Price gt 5.00
var regex = new System.Text.RegularExpressions.Regex(#"\/\$count\((.+)\)$");
var match = regex.Match(context.Request.Path.Value);
if(match != null && match.Success)
{
// So move the $filter expression to a query option
// We have to use redirect here, we can't affect the query inflight
context.Response.Redirect($"{context.Request.Uri.GetLeftPart(UriPartial.Authority)}{regex.Replace(context.Request.Path.Value, "/$count")}?{match.Groups[1].Value}");
}
else
await Next.Invoke(context);
}
}
Add to Startup.cs, before registering OData routes
app.Use(typeof(ODataConventionUrlRewriter));

Is is possible to use a custom resolver instead of the hubname attribute to resolve signalr hubs?

All of my SignalRHubs have their own service interface, this is used on the client side for type safe calling; ie no more referring to methods by string.
Anyways with this setup I have had to add a HubName attribute to all my hubs with the Interface name. Is it even possible to have the hubs resolved by these interfaces.
I did try replacing the resolver both in GlobalHost and in the HubConfiguration object with a Ninject resolver but it didn't seem to ever call the resolved for the hubs themselves.
Here is an example of a hub:
[HubName("IFoobarService")]
public class FoobarHub : Hub, IFoobarService
{
public void Baz(BazDto dto)
{
Clients.Others.Baz(dto);
}
}
}
Here is the code I used to try to bind my hubs with Ninject
kernel.Bind(x => x.FromThisAssembly()
.SelectAllClasses()
.InheritedFrom()
.BindAllInterfaces());
I think that using the HubName attribute is your best bet.
You could provide your own IHubDescriptorProvider and register it with SignalR's DependencyResolver, but I wouldn't recommend it.
You can take a look at the default IHubDescriptorProvider implemenation here: https://github.com/SignalR/SignalR/blob/2.0.2/src/Microsoft.AspNet.SignalR.Core/Hubs/Lookup/ReflectedHubDescriptorProvider.cs#L56
Notice the following line of code:
var hubDescriptors = types
.Select(type => new HubDescriptor
{
NameSpecified = (type.GetHubAttributeName() != null),
Name = type.GetHubName(),
HubType = type
});
Type.GetHubName() is implemented as an extension method here:
https://github.com/SignalR/SignalR/blob/2.0.2/src/Microsoft.AspNet.SignalR.Core/Hubs/Extensions/HubTypeExtensions.cs#L9
You could replace the ReflectedHubDescriptorProvider with your own IHubDescriptorProvider implementation that calls into your own GetHubName method, but I think that would be overkill.
Once again, I think using the HubName attribute is your best bet.

Using IOC Container for multiple concrete types

I want to implement IOC in my application but i am confused, in my application i have multiple concrete classes which implement an interface. Consider this scenario:-
I have an Inteface ICommand and following concrete types which implement this interface:-
AddAddress
AddContact
RemoveAddress
RemoveContact
Basically user performs all this action in UI and then List is passed to the service layer where each command is executed.
So in GUI layer I will write
ICommand command1 = new AddAddress();
ICommand command2 = new RemoveContact();
In command manger
List<ICommand> listOfCommands = List<ICommand>();
listOfCommands.Add(command1);
listOfCommands.Add(command2);
Then finally will pass listOfCommands to service layer.
Now as per my understanding of IOC is only one concrete class is mapped to the interface. And we use this syntax to get our concrete type from StructureMap container.
ICommand command = ObjectFactory.GetInstance<ICommand>();
How should i implement IOC in this scenario?
In this scenario you're better off making your commands into value objects, i.e. not created by the IoC container:
class AddAddressCommand {
public AddAddressCommand(string address) {
Address = address;
}
public string Address { get; private set; }
}
When you create a command, you really do want a specific implementation, and you want to parameterise it precisely, both concerns that will work against the services of the IoC container. This will become even more relevant if you decide at some point to serialize the command objects.
Instead, make the service-layer components that execute the commands into IoC-provided components:
class AddAddressHandler : IHandler<AddAddressCommand> {
public AddAddressHandler(ISomeDependency someDependency) { ... }
public void Handle(AddAddressCommand command) {
// Execution logic using dependencies goes here
}
}
In your case, the component that accepts the list of commands to execute will need to resolve the appropriate handler for each command and dispatch the command object to it.
There's some discussion of how to do this with Windsor here: http://devlicious.com/blogs/krzysztof_kozmic/archive/2010/03/11/advanced-castle-windsor-generic-typed-factories-auto-release-and-more.aspx - the community supporting your IoC container of choice will be able to help you with its configuration.
As mentioned by Mark, StructureMap will allow you to set up and call named instances of an interface:
ObjectFactory.Initialize(x =>
{
x.For<ISomeInterface>().Add<SomeImplementation>().Named("SomeName");
}
You can still add a default instance for that particular interface, of course:
ObjectFactory.Initialize(x =>
{
x.For<ISomeInterface>().Add<DefaultImplementation>();
x.For<ISomeInterface>().Add<SomeImplementation>().Named("SomeName");
}
When you call ObjectFactory.GetInstance<ISomeInterface>(); the default instance (the one initialized with Use instead of Add) is the one that will be returned.
So in your case, the set up would look something like:
ObjectFactory.Initialize(x =>
{
// names are arbitrary
x.For<ICommand>().Add<AddAddress>().Named("AddAddress");
x.For<ICommand>().Add<RemoveContact>().Named("RemoveContact");
}
These would be called as pointed out by Mark:
ObjectFactory.GetNamedInstance<ICommand>("AddAddress");
ObjectFactory.GetNamedInstance<ICommand>("RemoveContact");
Hope this helps.
Most IOC containers allow you to register "named instances" of interfaces, allowing you to register several implementations of ICommand, each with its own unique name. In StructureMap, you request them like this:
ObjectFactory.GetNamedInstance<ICommand>("AddAddress");
Have a look at this question to see how you setup the container in StructureMap.

Get instance of type inheriting from base class, implementing interface, using StructureMap

Continuing on my quest for a good plugin implementation I have been testing the StructureMap assembly scanning features.
All plugins will inherit from abstract class PluginBase. This will provide access to common application services such as logging. Depending on it's function, each plugin may then implement additional interfaces, for example, IStartUpTask.
I am initializing my plugins like so:
Scan(x => {
x.AssembliesFromPath(HttpContext.Current.Server.MapPath("~/Plugins"),
assembly => assembly.GetName().Name.Contains("Extension"));
x.AddAllTypesOf<PluginBase>();
});
The difficulty I am then having is how to work against the interface (not the PluginBase) in code. It's easy enough to work with PluginBase:
var plugins = ObjectFactory.GetAllInstances<PluginBase>();
foreach (var plugin in plugins)
{
}
But specific functionality (e.g. IStartUpTask.RunTask) is tied to the interface, not the base class.
I appreciate this may not be specific to structuremap (perhaps more a question of reflection).
Thanks,
Ben
Do you know all of the specific interfaces at registration time? If so, you can make a custom registration convention that registers each type with the plugin "family" of the interface it implements. An IRegistrationConvention gets each type, one at a time. You could do a simple check to see if the current type implements the desired interface, and if so, add it.
if (typeof(IStartUpTask).IsAssignableFrom(currentType)){
For<IStartUpTask>().Add(currentType);
}
Then later in the code, you can retrieve plugins for each specific interface individually:
var startupTasks = ObjectFactory.GetAllInstances<IStartUpTask>();
This approach has the benefit of allowing you to inject an enumerable of your custom interface plugins into a class that needs them, instead of making the service location call.
Alternatively, if you don't want to make a registration convention, you can just do the filtering at runtime using the handy OfType linq extension method:
var startupTasks = ObjectFactory.GetAllInstances<PluginBase>().OfType<IStartupTask>();
In case it helps others, I followed Joshua's advice and added my own registration convention:
public class PluginConvention : IRegistrationConvention
{
public void Process(Type type, Registry registry) {
if (type.BaseType == null) return;
if (type.BaseType.Equals(typeof(PSAdmin.Core.Domain.PluginBase))) {
if (typeof(IStartUpTask).IsAssignableFrom(type)) {
registry.For<IStartUpTask>()
.TheDefault.Is.OfConcreteType(type);
}
}
}
}
I couldn't get the .Add method to work, no matter what I tried, so had to use TheDefault.Is.OfConcreteType(type).
Then in my bootstrapper I am scanning like so:
Scan(x => {
x.AssembliesFromPath(HttpContext.Current.Server.MapPath("~/Plugins"),
assembly => assembly.GetName().Name.Contains("Extension"));
x.Convention<PluginConvention>();
});
I can then grab my IStartUp task types like so:
var plugins = ObjectFactory.GetAllInstances<IStartUpTask>();
foreach (var plugin in plugins)
{
plugin.Configure();
}
That said, after reading up on some of the new features of StructureMap, I'm not sure I need to do any of the above. For example I could just change my Scan delegate function to:
Scan(x => {
x.AssembliesFromPath(HttpContext.Current.Server.MapPath("~/Plugins"),
assembly => assembly.GetName().Name.Contains("Extension"));
x.AddAllTypesOf<PluginBase>();
});
And to use my interface concrete types (that inherit from PluginBase):
var tasks = ObjectFactory.Model.GetAllPossible<IStartUpTask>();
foreach (var task in tasks)
{
task.Configure();
}
Both methods seem to achieve the same thing.

Resources