My service uses a utility class and that utility class has several public properties. Is there something special I need call to ensure these public properties are setup?
The service uses a ASP.NET host. Inside of Global.ASAX I have declared a new AppHostBase:
public class MyServiceHost : AppHostBase
{
public MyServiceHost() : base("My Service Host", typeof(ServiceLibrary).Assembly) {}
public override void Configure(Funq.Container container)
{
container.Register<IDbConnectionFactory>(dbConFactory);
container.RegisterAutoWired<UtilityLibrary>();
container.RegisterAutoWired<RepositoryLibrary>();
}
}
Within both my repository library and utility library is a main class. This may class receives the Container and registers more specific utilities and repositories:
public class UtilityLibrary
{
public UtilityLibrary(Funq.Container container)
{
container.RegisterAutoWired<WidgetAActions>();
container.RegisterAutoWired<WidgetBActions>();
}
}
In the example below, WidgetARepository was set in the constructor of the RepositoryLibrary class. The RepositoryLibrary class, which contains the WidgetARepository, was supplied to the Container in the Configure method of the AppHost (first snippet above). Even still, the WidgetARepository (below) is never set:
public class WidgetAActions
{
public WidgetARepository WidgetARepository { get; set; }
public WidgetA Get(string id)
{
var item = this.WidgetARepository.Get(id);
if (item == null) { return null; }
// Do something else
return item;
}
}
Must I manually call Resolve()? This seems like it would defeat the purpose of injection by doing this.
If you are using wanting to use the Funq Container Autowire IoC outside of the ServiceStack service then you need to call Container.AutoWire yourself to have the container inject the relevant dependencies. This call is made behind the scenes in the ServiceStack request pipeline.
For ServiceStack v4:
HostContext.Container.AutoWire(objectToPopulate);
For ServiceStack v3:
AppHostBase.Instance.Container.AutoWire(objectToPopulate);
I would typically add this call to the construtor method of the object I want populated with the injections. So in your case:
public class WidgetAActions
{
public WidgetARepository WidgetARepository { get; set; }
public WidgetAActions()
{
// (Substitute with v3 usage if required.)
HostContext.Container.AutoWire(this);
}
...
}
Hope this helps.
Edit: Have you considered having the container inject the corresponding repository to WidgetAActions's constructor?
container.RegisterAutoWired<WidgetAActions>(c => new WidgetAActions(c.Resolve<WidgetARepository>()));
public class WidgetAActions
{
public WidgetARepository WidgetARepository { get; private set; }
public WidgetAActions(WidgetARepository repository)
{
WidgetARepository = repository;
}
...
}
Edit: Or you could resolve and set the public property of your object to the repository and then you don't have to have a constructor:
container.RegisterAutoWired<WidgetAActions>(c =>
new WidgetAActions { WidgetARepository = c.Resolve<WidgetARepository>() }
);
public class WidgetAActions
{
public WidgetARepository WidgetARepository { get; set; }
...
}
Or you could call autowire at time of resolving WidgetAActions:
container.RegisterAutoWired<WidgetAActions>(c => {
var actions = new WidgetAActions();
container.AutoWire(actions); // All dependencies injected
return actions;
});
public class WidgetAActions
{
public WidgetARepository WidgetARepository { get; 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 encoutered problem with unity, i want to use property injection, here is what i had in my code :
config of the container :
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<GTModelContainer, GTModelContainer>(new HttpContextLifetimeManager<GTModelContainer>())
.RegisterType<IUnitOfWork, UnitOfWorkGT>()
.RegisterType<ILogger, Logger>(new ContainerControlledLifetimeManager())
.RegisterType<ISocieteServices, SocieteServices>() ;
}
SocieteService Class :
public class SocieteServices : ISocieteServices
{
private IUnitOfWork UnitOfWork;
public SocieteServices(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork;
}
}
i tried to use property injection (i can't use constructor injection with custom data annotation) and here what i had done :
public class CodeSocieteUniqueAttribute : ValidationAttribute
{
[Dependency]
public ISocieteServices SocieteService {get; set;}
[InjectionMethod]
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
string codeSociete = value as string;
var societe = SocieteService.getSocieteByCode(codeSociete);
if (societe == null) return ValidationResult.Success;
else return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
}
the problem is that the societeService in CodeSocieteUniqueAttribute class is not injected.
Assuming that your class for registering types is publicly accessible and has a IUnityContainer object, ie:
public static class Resolver
{
public static IUnityContainer Container { get; set; }
public static void RegisterTypes(IUnityContainer container)
{
// type registrations here
container.RegisterType<GTModelContainer, GTModelContainer>(new HttpContextLifetimeManager<GTModelContainer>())
.RegisterType<IUnitOfWork, UnitOfWorkGT>()
.RegisterType<ILogger, Logger>(new ContainerControlledLifetimeManager())
.RegisterType<ISocieteServices, SocieteServices>() ;
// Now, set the container
Container = container;
}
}
You could access the container you've built up and resolve these types during method execution.
For instance,
public class CodeSocieteUniqueAttribute : ValidationAttribute
{
[Dependency]
public ISocieteServices SocieteService { get; set; }
[InjectionMethod]
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var societeServices = Resolver.Container.Resolve<ISocieteServices>();
SocieteService = societeServices; // Or, you know, just use this since it's resolved.
string codeSociete = value as string;
var societe = SocieteService.getSocieteByCode(codeSociete);
if (societe == null) return ValidationResult.Success;
else return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
}
This is actually pretty standard practice, and this MSDN article describes resolving items during runtime.
Another option is to pop the resolution into a default constructor like this:
public class CodeSocieteUniqueAttribute : ValidationAttribute
{
[Dependency]
public ISocieteServices SocieteService {get; set;}
public CodeSocieteUniqueAttribute()
{
var societeServices = Resolver.Container.Resolve<ISocieteServices>();
SocieteService = societeServices;
}
// the rest of the class omitted for brevity
}
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 must be overlooking something around getting the fluent-validation to fire within basic Service-Stack application I created.
I have been following the example found here. For the life of me I can't seem to get my validators fire????
Crumbs, there must be something stupid that I'm missing....???
I'm issuing a user request against the User-Service (http://my.service/users), the request goes straight through without invoking the appropriate validator registered.
Request is :
{"Name":"","Company":"Co","Age":10,"Count":110,"Address":"123 brown str."}
Response :
"user saved..."
Here is the code :
1.DTO
[Route("/users")]
public class User
{
public string Name { get; set; }
public string Company { get; set; }
public int Age { get; set; }
public int Count { get; set; }
public string Address { get; set; }
}
2.Validator
public class UserValidator : AbstractValidator<User>
{
public UserValidator()
{
RuleFor(r => r.Name).NotEmpty();
RuleFor(r => r.Age).GreaterThan(0);
}
}
3.AppHostBase
public class ValidationAppHost : AppHostBase
{
public ValidationAppHost()
: base("Validation Test", typeof(UserService).Assembly)
{
}
public override void Configure(Funq.Container container)
{
Plugins.Add(new ValidationFeature());
//This method scans the assembly for validators
container.RegisterValidators(typeof(UserValidator).Assembly);
}
}
4.Service
public class UserService : Service
{
public object Any(User user)
{
return "user saved...";
}
}
5.Global.asax.cs
protected void Application_Start(object sender, EventArgs e)
{
new ValidationAppHost().Init();
}
Ok....found the issue....I (in error) installed (via nuget) and referenced within my project the FluentValidation.dll with Service-Stack's FluentValidation implementation (see namespace ServiceStack.FluentValidation).
Once I removed this the sole incorrect FluentValidation reference and ensured that my validator extended from the service-stack implementation of the AbstractValidator the validators fired correctly...
I created a custom RegistrationFeature:
public class CustomRegistrationFeature: IPlugin
{
private string AtRestPath {get; set;}
public CustomRegistrationFeature ()
{
AtRestPath = "/register";
}
public void Register (IAppHost apphost)
{
appHost.RegisterService <CustomRegistrationService>(AtRestPath);
appHost.RegisterAs <CustomRegistrationValidator, IValidator <CustomRegistration>>();
}
}
I configured in AppHost:
Plugins.Add (new CustomRegistrationFeature ());
but in the metadata page there are CustomRegistration and Registration.
Why?
Thanks.
Update
The CustomRegistrationService:
[DefaultRequest(typeof(CustomRegistration))]
public class CustomRegistrationService : RegistrationService
{
public object Post(CustomRegistration request)
{
//base.Post( request);
return new CustomRegistrationResponse();
}
}
The CustomRegistration (Request dto):
[DataContract]
public class CustomRegistration : IReturn<CustomRegistrationResponse>
{
[DataMember]
public string Name{ get; set; }
}
The CustomRegistrationResponse (Response dto):
[DataContract]
public class CustomRegistrationResponse
{
[DataMember]
public string Test { get; set; }
}
The CustomRegistration service should appear although as we can't see the implementation of it, I can't tell if the service has been written correctly or not.
But there's no reason why Registration would appear in the /metadata pages since you haven't registered the RegistrationFeature.