简体   繁体   中英

C# (Web API) dependency injection (with Unity) return type Interface

I am building an WebApi with ASP.NET. Now I have divided my whole application into few layers and two of them are "interfaces" and "models" (every one of the layers has its own .dll). In "models.dll" all my models are defined and at application start injected where they're needed. So far so good. Now I am facing a problem when I am returning values from my controlles. Let's assume the following:

public class TestController : ApiController
{
    IBusinessObject _businessObject;

    public TestController(IBusinessObject businessObject)
    {
        this._businessObject= businessObject;
    }

    [Route("details/object/{id}")]
    [HttpGet]
    public ISomeObject GetObjectByNr(int id)
    {   
        return  this._businessObject.SearchForObject(id);
    }
}

Now when you look at GetObjectByNr you can see that the return type of it is ISomeObject (and of course the return type of this._businessObject.SearchForObject(id) is also ISomeObject) .The actual implementation of ISomeObject is inside of the ModelLayer but I don't want to include it into my WebApi project, because it shuold only communicate through the interfaces. Now when I run it like this I get an error which says that I should use a DataContractResolver (and something about serialization). I am aware that I cannot serialize an interface but I thought that my application is smart enough to find the right class to inject here (at start I do resolve all the interfaces and that works fine, when calling this._businessObject.SearchForObject(id) the right classes are being called and filled with right values, but just when returning the object at this point, I get the error). I have been looking at SO and found some "ways to go" for example the KnownType(typeof(SomeObject)) attribute. But when I try to set inside of TestController it is not being recognized (but even if that would work, it would need a reference to my actual model class and I don't want that).

Is there any way to make my interface serializable and to return the right object without actually telling my controller what the implementation of ISomeObject is?

thanks

EDIT:

Try using your own MediaTypeFormatter . You can use ie sharpSerializer, or Json.NET. There is information how to do this:

http://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters

http://www.asp.net/web-api/overview/advanced/configuring-aspnet-web-api

EDIT NOTE: The code below is targeting MVC Controller, not WebAPI ApiController.

If you are not bound to DataContractSerializer , you could use some other, like json serialization. For example, you can use Json.NET. The most convenient way is to override default Json result behaviour:

public class JsonNetResult : JsonResult
{

    public JsonSerializerSettings SerializerSettings { get; set; }
    public Formatting Formatting { get; set; }

    public JsonNetResult()
    {
        Formatting = Formatting.None;
        SerializerSettings = new JsonSerializerSettings();
        JsonRequestBehavior = JsonRequestBehavior.DenyGet;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        if (context == null)
            throw new ArgumentNullException("context");

        if (JsonRequestBehavior == JsonRequestBehavior.DenyGet
            && String.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException("This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet.");
        }

        HttpResponseBase response = context.HttpContext.Response;

        response.ContentType = !string.IsNullOrEmpty(ContentType)
                                    ? ContentType
                                    : "application/json";

        if (ContentEncoding != null)
            response.ContentEncoding = ContentEncoding;

        if (Data != null)
        {
            var writer = new JsonTextWriter(response.Output) { Formatting = Formatting };

            var serializer = JsonSerializer.Create(SerializerSettings);
            serializer.Serialize(writer, Data);

            writer.Flush();
        }
    }

Then in your controller class you override Json methods:

    protected override JsonResult Json(object data, string contentType, System.Text.Encoding contentEncoding)
    {
        return new JsonNetResult
        {
            ContentType = contentType,
            ContentEncoding = contentEncoding,
            Data = data
        };
    }

    protected override JsonResult Json(object data, string contentType, System.Text.Encoding contentEncoding, JsonRequestBehavior behavior)
    {
        return new JsonNetResult
        {
            ContentType = contentType,
            ContentEncoding = contentEncoding,
            Data = data,
            JsonRequestBehavior = behavior
        };
    }

And use it like this:

public ActionResult GetObjectByNr(int id)
{   
    return  Json(this._businessObject.SearchForObject(id), JsonRequestBehavior.AllowGet);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM