0

I'm currently implementing dependency injection in an existing ASP.NET Web API project using the Unity container.

I already manage to inject my service classes into my API controller by configuring a dependency resolver.

But for a controller function, I have to use a Data Transfer Object (DTO).
In that object, I can't find how to use my model contracts.

Here is the Web API controller method:

[HttpPost]
[Route("api/application/save")]
public IHttpActionResult SaveApplication(ApplicationUpdateDTO applicationUpdate)
{
    // Inner code calling service methods expecting IApplication and
    // collections of ITag as parameters.
}

And here is the DTO definition:

public class ApplicationUpdateDTO
{
    public IApplication Application { get; set; }
    public IEnumerable<int> DeletedTagIds { get; set; }
    public IEnumerable<ITag> AddedTags { get; set; }
    public IEnumerable<int> DeletedPlatformIds { get; set; }
    public IEnumerable<ITag> AddedPlatforms { get; set; }
}

As a result, the DTO itself is initialized, but not the properties that are all null.

I understand why the properties cannot be set : the interfaces cannot be instanciated and it doesn't have any clue of which classes to use for that. But my Unity container does, thanks to the registration.

  • Is it possible to use this "link" somehow to initialize the DTO properties?
  • Is there a better way do this?

Notes:

  • If I use implementations of my interfaces in the DTO, it obviously works fine.
  • The controller method receives a JSON object that is identical to my DTO.

edit

I also tried the implementation of a ModelBinder by referring to this post.
But for the line about the ValueProviderResult, I got a null value.

For convenience, here is the response from Todd in the other question:

public class CreateSomethingModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        string key = bindingContext.ModelName;
        ValueProviderResult val = bindingContext.ValueProvider.GetValue(key);
        if (val != null)
        {
            string s = val.AttemptedValue as string;
            if (s != null)
            {
                return new CreateSomething(){Title = s; UserId = new Guid(ControllerContext.HttpContext.Request.Headers["userId"]);}
            }
        }
        return null;
    }
}

The small difference I got from the response of the question, is the usage of the System.Web.Http.ModelBinding.IModelBinder instead of the MVC one.

As requested, here are exerpts of my interfaces.
The IApplication interface:

public interface IApplication
{
    /// <summary>
    /// Identifier of the application.
    /// </summary>
    int Id { get; set; }

    /// <summary>
    /// Name of the application.
    /// </summary>
    string Name { get; set; }

    /// <summary>
    /// Version of the application.
    /// </summary>
    string Version { get; set; }

    /// <summary>
    /// Tags associated to the application.
    /// </summary>
    ICollection<ITag> Tags { get; }
}

The ITag interface:

public interface ITag
{
    /// <summary>
    /// Identifier of the tag.
    /// </summary>
    int Id { get; set; }

    /// <summary>
    /// Identifier of the application to which the tag is linked.
    /// </summary>
    int ApplicationId { get; set; }

    /// <summary>
    /// Value of the tag.
    /// </summary>
    string Value { get; set; }
}

An example of JSON:

{
    "marketApplication": {
      "Id": 20,
      "Name": "MyApplication",
      "Version": "2.0"
    },
    "deletedTagIds": [],
    "addedTags": [
      {
        "Id": 0,
        "Value": "NewTag"
      }
    ],
    "deletedProgramIds": [],
    "addedPrograms": [
      {
        "Id": 0,
        "Name": "x86"
      }
    ]
}
Community
  • 1
  • 1
Niitaku
  • 835
  • 9
  • 19
  • Create a custom model binder to resolve the contract implementation when binging the model. in there you extract the segment that relates to your property and deserialize/resolve then assign to property – Nkosi Jan 17 '17 at 15:13
  • @Nkosi I effectively try to create a ModelBinder with the help of [this topic](http://stackoverflow.com/questions/38953348/model-bind-interface-property-with-web-api) but I retrieve a `null` for the `ValueProviderResult` (`ValueProviderResult valueProviderResult = bindingContext.ValueProvider.GetValue(key);`). I though then it was not the answer I'm looking for. – Niitaku Jan 17 '17 at 15:31
  • Give an example of the interface, its implementation and the JSON sent – Nkosi Jan 17 '17 at 15:55
  • 4
    Can you explain why you use interfaces instead of concrete classes for your DTOs? The use of interfaces are typically only beneficial when there is some behaviour you need to abstract. Abstracting data itself is typically not useful at all (since it's simply data). From that point of view it makes more sense to use the concrete classes directly and those can be model bound out of the box by Web API. – Steven Jan 17 '17 at 15:56
  • what to initialize in the contructor of the DTO itself? – federico scamuzzi Jan 17 '17 at 16:31
  • @Steven The thing I want to do is to reuse the existing contracts I created for other locations in the solution. I'm maybe wrong, but I want to abstract this in order to be able to receive any object on these properties that implement the corresponding interfaces (`IApplication` and `ITag`). It would save me the copy from a "sub-DTO" to a concrete one manually by using the matching type registered in my Unity container. Perhaps it is impossible? That is an implicit question in my original post. – Niitaku Jan 18 '17 at 08:06
  • @federicoscamuzzi Doesn't it expect an empty constructor (no parameters) to initialize the DTO? – Niitaku Jan 18 '17 at 08:07
  • but you can have it empty .. if you want just to initilize them to NON NULLABLE ..es: public class ApplicationUpdateDTO { public ApplicationUpdateDTO(){ Application = new Application(); DeletedTagIds = new List(); //Etc } public IApplication Application { get; set; } public IEnumerable DeletedTagIds { get; set; } public IEnumerable AddedTags { get; set; } public IEnumerable DeletedPlatformIds { get; set; } public IEnumerable AddedPlatforms { get; set; } } – federico scamuzzi Jan 18 '17 at 08:13
  • @federicoscamuzzi The idea is to retrieve the received data, not just to avoid `null` values. But you may mean that once initialized in ctor, it would be able to set the properties? If so, how can I use the registration link in my Unity container to use the correct type? – Niitaku Jan 18 '17 at 08:18
  • 1
    Create a custom model binder that looks up the type for the requested interface and hydrates it. – CodeCaster Jan 18 '17 at 08:55
  • @CodeCaster I tried to, like I wrote in my question post, but I got a `null`value. Would you be more specific? – Niitaku Jan 18 '17 at 09:27

1 Answers1

3

Dependency Injection is the practice of composing graphs of loosly coupled components. Components are the classes in your system that contain behaviour.

Dependency Injection is not meant to build up objects that merely contain data. Using Dependency Injection we build an graph of components. After that graph has been build (using constructor injection), we pass runtime data through this graph using method calls.

Every time you try to use Dependency Injection or an DI container (like Unity) for anything else, you will get into trouble. So although your question indicates that you want to do this with Unity, Unity should be left out of the equation (for this particular case).

As others already stated, the building of Data Transfer Objects (DTOs) that come in through the request is the job of Web API's Model Binder. The default Model Binders can't deserialize interfaces for you, which is quite obvious; to what implementation should they deserialize?

Although you can replace the default model binder, you should take a step back and look closely at what it is you are trying to achieve. You are abstracting away data. Hiding a DTO behind an abstraction makes usually little sense, since interfaces are meant to abstract behavior.

So instead of using interfaces, it is usually much better to use concrete classes instead.

it would save me the copy from a "sub-DTO" to a concrete one manually

Instead of doing that, a simpler approach would be to use composition. You can compose DTOs out of smaller DTOs. That would save you from having to do the copying completely.

by using the matching type registered in my Unity container.

This assumes that those DTOs should be registered in the container, but again, an DI container should not hold any runtime data. This should be kept out. Or as stated here:

Don't inject runtime data into application components during construction; it causes ambiguity, complicates the composition root with an extra responsibility and makes it extraordinarily hard to verify the correctness of your DI configuration. My advice is to let runtime data flow through the method calls of constructed object graphs.

Update

The idea of composition is simple, you build classes from smaller classes; rather than using inheritance or duplicating object structures. How this would look like in your case obviously depends on your needs, but I imagine that you wish to copy that ITag data to another class that has more properties:

public class SomeObject
{
    // Members:
    public string Name { get; set; }
    public string Description { get; set; }

    // Members to copy from ITag
    public int Id { get; set; }
    public int ApplicationId { get; set; }
    public string Value { get; set; }

    // more members
}

Instead, you can compose SomeObject from a concrete Tag DTO:

public class SomeObject
{
    // Members:
    public string Name { get; set; }
    public string Description { get; set; }

    public Tag Tag { get; set; }

    // more members
}

This way you don't have to copy Tag's members; you only have to set the Tag property with a reference to the deserialized Tag DTO.

Steven
  • 166,672
  • 24
  • 332
  • 435
  • Thanks for this explanation. I agree with you. Like I wrote in my question, I understand why it can't instantiate the DTO. What I wanted to achieve, is to **reuse** the interface; I've not created it for the DTO. Also, I wanted to **reuse** the link of the interface to the concrete class from the container, not directly use DI for it. I never wanted to register any DTO in the container, that is not relevant at all, I concede. The idea was to match concrete type for DTO's properties. I will then consider creating "sub-DTO". Can you tell me more about the _composition_ approach? – Niitaku Jan 18 '17 at 10:04
  • @Niitaku: See my update for information about composition. – Steven Jan 18 '17 at 10:41
  • If I understand well, it's just using object properties (where applicable) instead of exposing all properties? In my case, I'll have to transfer data from the DTO to an object that inherits from `IApplication` that have inside an `IEnumerable` of `ITag`. I have respectively concrete classes `Application` and `ApplicationTag` for my current context. I don't see how I can set the property `ITag` with a `TagDTO` object if it doesn't implement `ITag`, even if it has the same properties? Isn't it a suspicious cast? – Niitaku Jan 18 '17 at 11:00
  • @Niitaku: You are still talking about `IApplication` and `ITag` interfaces. Those interfaces should not exist. They serve no purpose. – Steven Jan 18 '17 at 11:16
  • For the DTO itself, they don't. But my services functions expect objects that at least implement properties defined by these interfaces. That's why I would need to retrieve the data from the DTO into objects that impletement my interfaces. I don't care if those objects implement additional properties, I just want to ensure they have the minimum required to perform some actions with them. That's also a purpose of interfaces, no? – Niitaku Jan 18 '17 at 12:56