I am trying to implement an interface as a service controller. I do not maintain this interface, so I am unable to modify it. For simplicity, let's say the interface looks like this:
public interface IFoo
{
string Bar(string A, int B);
}
For my controller, let's say it looks like this:
public class FooController : ApiController, IFoo
{
[Route("~/Foo/Bar")]
[HttpGet]
public string Bar(string optionalA, int requiredB)
{
return DoStuff(optionalA, requiredB);
}
}
With this setup, how can I decorate A as Optional and B as Required without changing IFoo (i.e. cannot reorder A and B) and while still having my controller implement IFoo? By default, all string parameters are considered Required unless I pull them into a class at which point they revert to defaulting to Optional unless I decorate them with a RequiredAttribute but I cannot do that here because that would require either changing IFoo or would break my requirement to implement IFoo with this controller class.
Is there a straight up way to do this in a way that Swagger & Swagger UI honors it? I'd like to avoid this hacky solution:
public class FooController : ApiController, IFoo
{
[Route("~/Foo/Bar")]
[HttpGet]
public string FakeBar(MyDto data)
{
return Bar(data.optionalA, data.requiredB);
}
[ApiExplorerSettings(IgnoreApi = true)]
public string Bar(string optionalA, int requiredB)
{
return DoStuff(optionalA, requiredB);
}
}
public class MyDto
{
// defaults to optional here
public string optionalA { get; set; }
[Required]
public int requiredB { get; set; }
}
I do understand that if I could reorder A and B (that's not an option) then the simple solution is this:
public string Bar(int requiredB, string optionalA = null)
I have found that I am unable to accomplish this. I am forced to either change the interface or not implement the interface or some other nasty thing that causes way too much additional code. At this time, I think there is just no other way to directly control the requiredness of a parameter to an action handler.
Will gladly defer to anybody who corrects me though! ;-)
Related
I want to inject all instances as IEnumerable<T> that implement a common interface. It is for using it in a strategy pattern resolver. How can I do it? I googled that unity container has a way.
I need this to do the same job as link below.
https://ufukhaciogullari.com/blog/strategy-pattern-with-dependency-injection/
public interface ITest
{
string Name { get; set; }
}
public class TestA : ITest
{
public string Name { get; set; } = "A";
}
public class TestB : ITest
{
public string Name { get; set; } = "B";
}
public class TestC : ITest
{
public string Name { get; set; } = "C";
}
public class SomeResolver
{
IEnumerable<ITest> _tests;
public SomeResolver(IEnumerable<ITest> tests)
{
_tests = tests;
}
}
In unity, I can register the following way:
container.RegisterType<IEnumerable<IParserBuilder>, IParserBuilder[]>();
I tried to do the same in Prism, but it fails. How to do it in Prism?
I tried to do the same in Prism, but it fails. How to do it in Prism?
Prism's no dependency injection container, it just tries to hide IUnityContainer from you.
That being said, there's no need to register the IEnumerable<IParserBuilder> in the first place.
container.Resolve<SomeResolver>()
will call the constructor and pass it instances of TestA, TestB and TestC, given you registered them first.
container.Register<ITest, TestA>( "A" );
container.Register<ITest, TestB>( "B" );
container.Register<ITest, TestC>( "C" );
Unfortunately, there's no way to have those A, B and C injected, too, so you have to keep the Name property if you need to identify a specific service (I'd make it read-only, though). I'd love to be able to inject IEnumerable<(string, ITest)> and get the names, too...
Hi I would want to have validations something of this sort
[RequiredCustom(ActionType=(int)Action.Update, ActionType=(int)Action.Delete)]
public string NotesID { get; set; }
[Required]
[RegularExpression("1|2|3|4")]
public int ActionType { get; set; }
I would want to validate this NotesID only when Updation and Deletion is taking place. I don't need any javascript code for unobtrusive and all. I just want server side validation.
Please don't suggest use of separate models I can't do that. Something similar solution will also do.
Let me know if this requires more clarification, Any help would be greatly appreciated.
If you are ok with placing the validation data annotations on the class itself, you could do something like the answer to this post (by Gary.S) suggests.
Here
In essense, just create a new custom validation attribute and since its an attribute at class level, you will have access to the object itself and hence access to other properties.
You custom attribute should look something like this (Assuming your class name is 'Notes')
public class RequiredCustom: ValidationAttribute
{
List<int> actions;
public RequiredCustom(int[] actions)
{
this.actions = new List<int>();
this.actions.AddRange(actions);
}
public override bool IsValid(object value)
{
bool isValid = true;
Notes testVal = value as Notes;
if(this.actions.Contains((int)testVal.Action))
{
if(string.IsNullOrWhiteSpace(testVal.NotesID))
{
isValid = false;
}
}
return isValid;
}
}
Then, add the validation attribute on the class and send the array of enums you want to test for. This way it will be dynamic enough to send other later. In this case, I am sending an ARRAY of Update and Delete enums since you have a special case for these two.
[RequiredCustom(new int[] {(int)Action.Update, (int)Action.Delete)}]
public class Notes
{
public string NotesID { get; set; }
[Required]
[RegularExpression("1|2|3|4")]
public int ActionType { get; set; }
}
Remember, this will work only if you set the attribute on the class, not on the NotesId property.
Is it possible to pass an ViewModel object to WebApi controller action instead of separate params?
Instead of using:
public class ContactsController : ApiController
{
public IEnumerable<Contact> GetContacts(string p1, string p2)
{
// some logic
}
}
I would like to use:
public class ContactsController : ApiController
{
public IEnumerable<Contact> GetContacts(TestVM testVM)
{
// some logic
}
}
public class TestVM
{
public string P1 { get; set; }
public string P2 { get; set; }
}
This doesn't seem to work for me. When I call /api/contacts/?P1=aaa&P2=bbb the testVM object doesn't get populated (null).
Also, I would like the TestVM to have valdiation attribtues defined and use ModelState.IsValid in my API controller.
Unless told otherwise WebApi will deserialise complex models using the content/body of the request. To tell WebApi to use the Url to construct the model you need to specify the [FromUri] attribute:
public IEnumerable<Contact> GetContacts([FromUri]TestVM testVM)
{
// some logic
}
I know it's kind of late to post another answer but I thought it could be useful for anyone who uses .net core as a web API service
public IEnumerable<Contact> GetContacts([FromQuery]TestVM testVM)
Does anyone know if it's possible to use Ninject to resolve any unresolved abstract dependencies outside of the instantiation process? I've just been looking into constructor injection vs property/method/field injection, but it looks to me as though Ninject is still expecting to be the creator of the type using the IKernel.Get<>() method.
Basically, we're using MVC3 to build our product, and we've come up against a situation where we want the default ModelBinder to map form values to an instance of the object, and then be able to call a method on the submitted ViewModel that is dependent on an abstract interface e.g.
public class InviteFriend {
[Required]
public string EmailAddress { get; set; }
public void Execute() {
var user = IUserRepository.GetUser(this.EmailAddress);
if (user == null) {
IUserRepository.SaveInvite(this.EmailAddress);
}
MailMessage toSend = new MailMessage(); // Obviously some logic to prepare the body, subject and other mail properties
SmtpClient.Send(toSend);
}
}
where the controller action would receive InviteFriend as the method argument. We want Ninject to be able to resolve that IUserRepository dependency, but I can't quite work out how to since the object itself is instantiated by the MVC ModelBinder rather than Ninject IKernel.Get<>().
Maybe the solution is a Ninject-based ModelBinder, or does that seem a really bad idea?
EDIT TO ADD: After the comments below, I realise that my hastily mocked-up code sample doesn't really reflect what we're facing. I've updated the code sample to reflect that the logic for InviteFriend.Execute() is more complex than just calling a method on one repository. Potentially, this is logic representing a discrete task that could co-ordinate interactions between multiple different domain objects and multiple repositories. The repositories are defined abstractly, and ideally would be resolved by Ninject.
I think what you are looking for is somewhat the following scenario:
public class InviteFriend {
[Required]
public string EmailAddress { get; set; }
// More information
}
public interface ICommand {
void Execute();
}
public class InviteFriendCommand : ICommand
{
public InviteFriend(InviteFriend info, IUserRepository userRepo, IMailSender mailSender) {
this.inviteFriend = info;
this.userRepo = userRepo;
this.mailSender = mailSender;
}
public void Execute() {
var user = this.userRepo.GetUser(this.inviteFriend.EmailAddress);
if (user == null) {
this.userRepo.SaveInvite(this.inviteFriend.EmailAddress);
}
MailMessage toSend = new MailMessage(); // Obviously some logic to prepare the body, subject and other mail properties
this.mailSender.Send(toSend);
}
}
public interface ICommandFactory {
ICommand CreateInviteFriendCommand(InviteFriend info);
}
public class CommandFactory {
public CommandFactory(IResolutionRoot resolutionRoot) {
this.resolutionRoot = resolutionRoot;
}
ICommand CreateInviteFriendCommand(InviteFriend info) {
this.resolutionRoot.Get<InviteFriendCommand>(new ConstructorArgument("info", info));
}
}
public class YourController {
// Somewhere
var command = this.commandFactory.CreateInviteFriendCommand(info);
command.Execute();
}
public class YourModule : NinjectModule {
override Load() {
Bind<IUserRepository>().To<UserRepo>().InRequestScope();
Bind<ICommandFactory>().To<CommandFactory>().InRequestScope();
Bind<InviteFriendCommand>().ToSelf().InRequestScope();
}
}
Forgive me when you need to tweak it a bit. I hacked it together with my out of brain compiler ;)
Thank you for all your comments, but I've subsequently found the information I was looking for.
The answer is that it is possible to inject dependencies post-instantiation with Ninject. The solution is as follows:
public class InviteFriend {
[Inject]
public IUserRepository UserRepo { get; set; }
[Required]
public string EmailAddress { get; set; }
public void Execute() {
var user = UserRepo.GetUser(this.EmailAddress);
if (user == null) {
UserRepo.SaveInvite(this.EmailAddress);
}
MailMessage toSend = new MailMessage(); // Obviously some logic to prepare the body, subject and other mail properties
SmtpClient.Send(toSend);
}
}
With client code then using the Ninject kernel as follows:
IKernel container = new StandardKernel(new ModuleWithMyBindings());
container.Inject(instanceOfInviteFriend);
The code itself is a bit more sophisticated than that i.e. I'm not instantiating a new IKernel each time I need it.
I realise that this is architecturally less pure than some of the suggestions put forward in comments, but in the spirit of YAGNI, this is good enough for now and we can always refactor later on with some of the good suggestions in Daniel's answer. However, this was a question about the capabilities of Ninject rather than an architectural review question, and this is what I consider the answer to my own question :)
I have a repository pattern i created on top of the ado.net entity framework. When i tried to implement StructureMap to decouple my objects, i kept getting StackOverflowException (infinite loop?). Here is what the pattern looks like:
IEntityRepository where TEntity : class
Defines basic CRUD members
MyEntityRepository : IEntityRepository
Implements CRUD members
IEntityService where TEntity : class
Defines CRUD members which return common types for each member.
MyEntityService : IEntityService
Uses the repository to retrieve data and return a common type as a result (IList, bool and etc)
The problem appears to be with my Service layer. More specifically with the constructors.
public PostService(IValidationDictionary validationDictionary)
: this(validationDictionary, new PostRepository())
{ }
public PostService(IValidationDictionary validationDictionary, IEntityRepository<Post> repository)
{
_validationDictionary = validationDictionary;
_repository = repository;
}
From the controller, i pass an object that implements IValidationDictionary. And i am explicitly calling the second constructor to initialize the repository.
This is what the controller constructors look like (the first one creates an instance of the validation object):
public PostController()
{
_service = new PostService(new ModelStateWrapper(this.ModelState));
}
public PostController(IEntityService<Post> service)
{
_service = service;
}
Everything works if i don't pass my IValidationDictionary object reference, in which case the first controller constructor would be removed and the service object would only have one constructor which accepts the repository interface as the parameter.
I appreciate any help with this :) Thanks.
It looks like the circular reference had to do with the fact that the service layer was dependent on the Controller's ModelState and the Controller dependent on the Service layer.
I had to rewrite my validation layer to get this to work. Here is what i did.
Define generic validator interface like below:
public interface IValidator<TEntity>
{
ValidationState Validate(TEntity entity);
}
We want to be able to return an instance of ValidationState which, obviously, defines the state of validation.
public class ValidationState
{
private readonly ValidationErrorCollection _errors;
public ValidationErrorCollection Errors
{
get
{
return _errors;
}
}
public bool IsValid
{
get
{
return Errors.Count == 0;
}
}
public ValidationState()
{
_errors = new ValidationErrorCollection();
}
}
Notice that we have an strongly typed error collection which we need to define as well. The collection is going to consist of ValidationError objects containing the property name of the entity we're validating and the error message associated with it. This just follows the standard ModelState interface.
public class ValidationErrorCollection : Collection<ValidationError>
{
public void Add(string property, string message)
{
Add(new ValidationError(property, message));
}
}
And here is what the ValidationError looks like:
public class ValidationError
{
private string _property;
private string _message;
public string Property
{
get
{
return _property;
}
private set
{
_property = value;
}
}
public string Message
{
get
{
return _message;
}
private set
{
_message = value;
}
}
public ValidationError(string property, string message)
{
Property = property;
Message = message;
}
}
The rest of this is StructureMap magic. We need to create validation service layer which will locate validation objects and validate our entity. I'd like to define an interface for this, since i want anyone using validation service to be completely unaware of the StructureMap presence. Besides, i think sprinkling ObjectFactory.GetInstance() anywhere besides the bootstrapper logic a bad idea. Keeping it centralized is a good way to insure good maintainability. Anyway, i use the decorator pattern here:
public interface IValidationService
{
ValidationState Validate<TEntity>(TEntity entity);
}
And we finally implement it:
public class ValidationService : IValidationService
{
#region IValidationService Members
public IValidator<TEntity> GetValidatorFor<TEntity>(TEntity entity)
{
return ObjectFactory.GetInstance<IValidator<TEntity>>();
}
public ValidationState Validate<TEntity>(TEntity entity)
{
IValidator<TEntity> validator = GetValidatorFor(entity);
if (validator == null)
{
throw new Exception("Cannot locate validator");
}
return validator.Validate(entity);
}
#endregion
}
I'm going to be using validation service in my controller. We could move it to the service layer and have StructureMap use property injection to inject an instance of controller's ModelState to the service layer, but i don't want the service layer to be coupled with ModelState. What if we decide to use another validation technique? This is why i'd rather put it in the controller. Here is what my controller looks like:
public class PostController : Controller
{
private IEntityService<Post> _service = null;
private IValidationService _validationService = null;
public PostController(IEntityService<Post> service, IValidationService validationService)
{
_service = service;
_validationService = validationService;
}
}
Here i am injecting my service layer and validaton service instances using StructureMap. So, we need to register both in StructureMap registry:
ForRequestedType<IValidationService>()
.TheDefaultIsConcreteType<ValidationService>();
ForRequestedType<IValidator<Post>>()
.TheDefaultIsConcreteType<PostValidator>();
That's it. I don't show how i implement my PostValidator, but it's simply implementing IValidator interface and defining validation logic in the Validate() method. All that's left to do is call your validation service instance to retrieve the validator, call the validate method on your entity and write any errors to ModelState.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude = "PostId")] Post post)
{
ValidationState vst = _validationService.Validate<Post>(post);
if (!vst.IsValid)
{
foreach (ValidationError error in vst.Errors)
{
this.ModelState.AddModelError(error.Property, error.Message);
}
return View(post);
}
...
}
Hope i helped somebody out with this :)
I used a similar solution involving a generic implementor of IValidationDictionary uses a StringDictionary and then copied the errors from this back into the model state in the controller.
Interface for validationdictionary
public interface IValidationDictionary
{
bool IsValid{get;}
void AddError(string Key, string errorMessage);
StringDictionary errors { get; }
}
Implementation of validation dictionary with no reference to model state or anything else so structuremap can create it easily
public class ValidationDictionary : IValidationDictionary
{
private StringDictionary _errors = new StringDictionary();
#region IValidationDictionary Members
public void AddError(string key, string errorMessage)
{
_errors.Add(key, errorMessage);
}
public bool IsValid
{
get { return (_errors.Count == 0); }
}
public StringDictionary errors
{
get { return _errors; }
}
#endregion
}
Code in the controller to copy the errors from the dictionary into the model state. This would probably be best as an extension function of Controller.
protected void copyValidationDictionaryToModelState()
{
// this copies the errors into viewstate
foreach (DictionaryEntry error in _service.validationdictionary.errors)
{
ModelState.AddModelError((string)error.Key, (string)error.Value);
}
}
thus bootstrapping code is like this
public static void BootstrapStructureMap()
{
// Initialize the static ObjectFactory container
ObjectFactory.Initialize(x =>
{
x.For<IContactRepository>().Use<EntityContactManagerRepository>();
x.For<IValidationDictionary>().Use<ValidationDictionary>();
x.For<IContactManagerService>().Use<ContactManagerService>();
});
}
and code to create controllers is like this
public class IocControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
return (Controller)ObjectFactory.GetInstance(controllerType);
}
}
Just a quick query on this. It's helped me out quite a lot so thanks for putting the answer up, but I wondered which namespace TEntity exists in? I see Colletion(TEntity) needs System.Collections.ObjectModel. My file compiles without anything further but I see your TEntity reference highlighted in Blue which suggests it has a class type, mine is Black in Visual Studio. Hope you can help. I'm pretty keen to get this working.
Have you found any way to seperate validation into the service layer at all? My gut tells me that validating in the Controller is a bit smelly but I've looked high and low to find a way to pass validation error messages back to the controller without tightly coupling the service layer to the controller and can't find anything. :(
Again, thanks for the great post!
Lloyd