c# - WebApi 2 return types -
i'm looking @ documentation of webapi 2
, , i'm severely disappointed way action results architected. hope there better way.
so documentation says can return these:
**void** return empty 204 (no content) **httpresponsemessage** convert directly http response message. **ihttpactionresult** call executeasync create httpresponsemessage, convert http response message. **other type** write serialized return value response body; return 200 (ok).
i don't see clean way return array of items custom http status code, custom headers , auto negotiated content though.
what see like
public httpresult<item> post() { var item = new item(); var result = new httpresult<item>(item, httpstatuscode.created); result.headers.add("header", "header value"); return result; }
this way can glance on method , see whats being returned, , modify status code , headers.
the closest thing found negotiatedcontentresult<t>
, weird signature (why need instance of controller?), there's no way set custom headers?
is there better way ?
i don't think designers of web-api intended controller methods fiddling headers. design pattern seems to use delegatinghandler, actionfilterattribute , executeasync overridable method of apicontroller handle authentication , response formatting.
so perhaps logic message content negotiation should handled there ?
however if need control headers within controller method can little set-up make work. can create own delegationhandler forwards selected headers "inner" response headers:
public class messagehandlerbranding : delegatinghandler { protected async override task<httpresponsemessage> sendasync(httprequestmessage request, cancellationtoken cancellationtoken) { var response = await base.sendasync(request, cancellationtoken); //if want forward headers inner content can this: if (response.content != null && response.content.headers.any()) { foreach (var hdr in response.content.headers) { var keyupr = hdr.key.toupper(); //response not tolerate setting of header values if ( keyupr != "content-type" && keyupr != "content-length") { string val = hdr.value.any() ? hdr.value.firstordefault() : ""; response.headers.add(hdr.key, val); } } } //add our branding header each response response.headers.add("x-powered-by", "my product"); return response; } }
then register handler in web-api configuration, in globalconfig.cs file.
config.messagehandlers.add(new messagehandlerbranding());
you write own custom class response object this:
public class apiqueryresult<t> : ihttpactionresult t : class { public apiqueryresult(httprequestmessage request) { this.statuscode = httpstatuscode.ok; ; this.headerstoadd = new list<mystringpair>(); this.request = request; } public httpstatuscode statuscode { get; set; } private list<mystringpair> headerstoadd { get; set; } public t content { get; set; } private httprequestmessage request { get; set; } public void addheaders(string headerkey, string headervalue) { this.headerstoadd.add(new mystringpair(headerkey, headervalue)); } public task<httpresponsemessage> executeasync(cancellationtoken cancellationtoken) { var response = this.request.createresponse<t>(this.statuscode, this.content); foreach (var hdr in this.headerstoadd) { response.content.headers.add(hdr.key, hdr.value); } return task.fromresult(response); } private class mystringpair { public mystringpair(string key, string value) { this.key = key; this.value = value; } public string key; public string value; } }
and use in controller:
[httpget] public apiqueryresult<customersview> customersviewsrow(int id) { var ret = new apiqueryresult<customersview>(this.request); ret.content = this.bll.getonecustomer(id); ret.addheaders("mycustomhkey","mycustomvalue"); return ret; }