I'm using MassTransit (5.5.5) with StructureMap (4.7) in a large code base, using Registry classes to keep my dependencies organized, following what's outlined here:
class BusRegistry : Registry
{
public BusRegistry()
{
For<IBusControl>(new SingletonLifecycle())
.Use(context => Bus.Factory.CreateUsingInMemory(x =>
{
x.ReceiveEndpoint("customer_update_queue", e => e.LoadFrom(context));
}));
Forward<IBusControl, IBus>();
}
}
// Snip...
public void CreateContainer()
{
_container = new Container(x => {
x.AddRegistry(new BusRegistry());
});
}
However, the LoadFrom extension method used in the call to ReceiveEndpoint is deprecated. So how is one supposed to use MassTransit with StructureMap Registry classes currently?
There probably isn't going to be a good answer, since StructureMap is on its way out. I ended up not using StructureMap for consumer configuration:
class BusRegistry : Registry
{
public BusRegistry()
{
For<IBusControl>(new SingletonLifecycle())
.Use(context => Bus.Factory.CreateUsingInMemory(x =>
{
x.ReceiveEndpoint("customer_update_queue", endpointCfg => {
endpointCfg.Consumer<FirstSubscriber>(
GetFirstSubscriberFactoryMethod()
);
endpointCfg.Consumer<SecondSubscriber>(
GetSecondSubscriberFactoryMethod()
);
// etc...
});
}));
Forward<IBusControl, IBus>();
}
}
...though I am using StructureMap to inject dependencies into the consumers.
Related
Is it possible to access instance of DI configured services inside HostBuilder() configuration?
here is what I meant:
return new HostBuilder()
.UseOrleans((cntx, builder) =>
{
builder.ConfigureApplicationParts(parts =>
{
// This is where I want to access instance of IMyService
// in order to help Orleans builder to configure Orleans properly
}
})
.ConfigureServices(services =>
{
services.AddSingleton<IMyService, MyService>();
})
.RunConsoleAsync();
In case this turns out to be an XY problem, and you are you trying to create some startup task, there is a AddStartupTask extension
return new HostBuilder()
.UseOrleans((cntx, builder) => {
//Add a startup task to be executed when the silo has started.
builder.AddStartupTask((sp, token) => {
// access instance of IMyService
IMyService service = sp.GetRequiredService<IMyService>();
//...use service as needed
return Task.CompletedTask;
});
})
.ConfigureServices(services => {
services.AddSingleton<IMyService, MyService>();
})
.RunConsoleAsync();
Need some help here please ...
I'm looking at the example "graphql-dotnet/server" where the exposed objects contains just plain properties. But what if I need to resolve a property and get data from a repository, how can I get hold of the respository class in the Type-class?
Example:
The sample has a ChatQuery exposing "messages".
public ChatQuery(IChat chat)
{
Field<ListGraphType<MessageType>>("messages", resolve: context => chat.AllMessages.Take(100));
}
Instance "chat" is the repository here and is serving data (messages) via chat.AllMessages.
Let's say that a message has a list of viewers. Then I need to resolve that list from a repository. This is done in the other example "graphql-dotnet/examples" where the "StarWars/Types/StarWarsCharacter.cs" has a list of friends and the "StarWars/Types/HumanType" has the repository (StarWarsData) inserted in the constructor and can be used in the resolve method for "friends":
public class HumanType : ObjectGraphType<Human>
{
public HumanType(StarWarsData data)
{
Name = "Human";
Field(h => h.Id).Description("The id of the human.");
Field(h => h.Name, nullable: true).Description("The name of the human.");
Field<ListGraphType<CharacterInterface>>(
"friends",
resolve: context => data.GetFriends(context.Source)
);
Field<ListGraphType<EpisodeEnum>>("appearsIn", "Which movie they appear in.");
Field(h => h.HomePlanet, nullable: true).Description("The home planet of the human.");
Interface<CharacterInterface>();
}
}
BUT, doing the same thing in the server sample won't work.
public class MessageType : ObjectGraphType<Message>
{
public MessageType(IChat chat)
{
Field(o => o.Content);
Field(o => o.SentAt);
Field(o => o.From, false, typeof(MessageFromType)).Resolve(ResolveFrom);
Field<ListGraphType<Viewer>>(
"viewers",
resolve: context => chat.GetViewers(context.Source)
);
}
private MessageFrom ResolveFrom(ResolveFieldContext<Message> context)
{
var message = context.Source;
return message.From;
}
}
When I add the chat repository to the constructor in MessageType it fails.
I'm obviously missing something here; why isn't Dependency Injection injecting the chat instance into the MessageType class in the "graphql-dotnet/server" project?
But it works in the "graphql-dotnet/examples" project.
Best,
Magnus
To use DI you need to pass a dependency resolver in the constructor of your Schema class. The default resolver uses Activator.CreateInstance, so you have to teach it about the Container you are using.
services.AddSingleton<IDependencyResolver>(
s => new FuncDependencyResolver(s.GetRequiredService));
IDependecyResolver is an interface in the graphql-dotnet project.
public class StarWarsSchema : Schema
{
public StarWarsSchema(IDependencyResolver resolver)
: base(resolver)
{
Query = resolver.Resolve<StarWarsQuery>();
Mutation = resolver.Resolve<StarWarsMutation>();
}
}
https://github.com/graphql-dotnet/examples/blob/bcf46c5c502f8ce75022c50b9b23792e5146f6d2/src/AspNetCore/Example/Startup.cs#L20
https://github.com/graphql-dotnet/examples/blob/bcf46c5c502f8ce75022c50b9b23792e5146f6d2/src/StarWars/StarWarsSchema.cs#L6-L14
my first question that I can't find the exact answer elsewhere.
Using Automapper 4.2.1, Unity 4.01
I'm trying to have an Automapper profile call my service interface again to get a nested object to map to my destination property. Ultimately I would prefer to not use ResolveUsing, but if that works that is fine with me.
public class HeadlineMap : Profile
{
private readonly IDeserializeModels _deserialize;
public HeadlineMap(IDeserializeModels argDeserializeModels)
{
_deserialize = argDeserializeModels;
}
protected override void Configure()
{
CreateMap<LiveSiteHeadline, Headline>().
...
ForMember(t => t.VideoTitle, options => options.MapFrom(f => f.videoTitle)).
ForMember(t => t.Disclaimer, options => options.ResolveUsing<ResolveDisclaimerReference>().ConstructedBy(()=> new ResolveDisclaimerReference(_deserialize)));
}
}
public class ResolveDisclaimerReference : ValueResolver<LiveSiteHeadline, Object>
{
private readonly IDeserializeModels _deserialize;
public ResolveDisclaimerReference(IDeserializeModels argDeserializeModels)
{
_deserialize = argDeserializeModels;
}
protected override object ResolveCore(LiveSiteHeadline source)
{
return _deserialize.GetResponseObject(source.disclaimer.urlPattern, source.disclaimer.project, source.disclaimer.path);
}
}
I'm using the recommended 4.2.1 way of registering all of my maps within the Unity container:
var config = new MapperConfiguration(cfg =>
{
foreach (var profile in profiles)
{
cfg.AddProfile(profile);
}
});
container.RegisterType<MapperConfiguration>(new ContainerControlledLifetimeManager(),
new InjectionFactory(c => config))
.RegisterType<IMapper>(new InjectionFactory(c => c.Resolve<MapperConfiguration>().CreateMapper()));
But when I run the above I get -
"Missing type map configuration or unsupported mapping.".
Any ideas on what I'm missing? The other examples using ObjectFactory, Ninject don't seem to work as I must not be using those.
Can I override service mapping for StructureMap settings of added registry:
return new Container(x => {
For<IService>().Use<OverridenService>
x.AddRegistry<MyRegistry>();
For<IService>().Use<OverridenService>
}
public class MyRegistry: Registry
{
public MyRegistry()
{
For<IService>().Use<MyService>
}
}
I want OverridenService to be instantiated, but StructureMap instantiates MyService always
So, let's say you have this code (this code assigns the container to a variable that you can later return):
var container = new Container(x =>
{
x.AddRegistry<MyRegistry>();
});
You can simply use the Configure method like this:
container.Configure(x => x.For<IService>().Use<OverridenService>());
guys,
At this point i am close to start pulling hair out of my head. I don't find a way to achieve this.
I have a custom class that belongs to a custom folder i created under my WebServices Module src folder. I need to be able to instantiate this class from inside another module/controller but when i do that and dump the services member it contains null.
How can i have the service manager accesible from inside my ApiAuthentication class.
Any help will be appreciated. Thanks
<?php
namespace WebServices\Services;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class ApiAuthenticationService extends \Zend\Soap\Client implements ServiceLocatorAwareInterface{
public $services;
function __construct($options = null){
parent::__construct('http://tinysoa.local/soap/security/api_authentication?wsdl',$options);
}
public function setServiceLocator(ServiceLocatorInterface $locator)
{
$this->services = $locator;
}
public function getServiceLocator()
{
return $this->services;
}
}
When i call this from inside another module/controller it dumps a null value:
class IndexController extends AbstractActionController
{
public function indexAction()
{
$a = new \WebServices\Services\ApiAuthenticationService();
var_dump($a->services);
Responding with my own answer to add-on to Adrian's, and the question you asked in response.
If your service has dependencies of it's own, you just use a factory instead of going the invokable route.
Say your service needs a cache adapter and database adapter. Also imagine that it can optionally be configured with some other service (FooService, below):
<?php
public function getServiceConfig()
{
return array(
'factories' => array(
'my_service' => function($sm){
$cache = $sm->get('Cache');
$dbAdapter = $sm->get('DefaultDbAdapter');
$fooService = $sm->get('FooService');
// instantiate your service with required dependencies
$mySvc = new \My\Shiny\Service($cache, $dbAdapter);
// inject an optional dependency
$mySvc->setFooService($fooService);
// return your shiny new service
return $mySvc;
}
)
);
}
Side Note: It's generally bad design to inject the ServiceManager all over the place. You're better off managing your dependencies more explicitly, like above.
This stuff is covered quite well in the Quick Start, if you haven't already read that.
Register your Service in Service Config and access it through getServiceLocator() method in controller.
Module.php
public function getServiceConfig()
{
return array(
'invokables' => array(
'my_service' => 'WebServices\Services\ApiAuthenticationService'
)
);
}
Controller
public function indexAction()
{
$service = $this->getServiceLocator()->get('my_service');
}