2012-05-18 17 views
157

से http स्थिति कोड लौटा रहा है मैं एक वेब एपीआई नियंत्रक में एक जीईटी विधि के लिए संशोधित 304 का स्टेटस कोड वापस करने की कोशिश कर रहा हूं।वेब एपीआई नियंत्रक

एक ही रास्ता मैं सफल रहा कुछ इस तरह था:

public class TryController : ApiController 
{ 
    public User GetUser(int userId, DateTime lastModifiedAtClient) 
    { 
     var user = new DataEntities().Users.First(p => p.Id == userId); 
     if (user.LastModified <= lastModifiedAtClient) 
     { 
      throw new HttpResponseException(HttpStatusCode.NotModified); 
     } 
     return user; 
    } 
} 

समस्या यहाँ है कि यह एक अपवाद नहीं है, यह सिर्फ संशोधित नहीं कर रहा है तो ग्राहक संचय ठीक है। मैं भी वापसी प्रकार को उपयोगकर्ता होना चाहता हूं (जैसा कि सभी वेब एपीआई उदाहरण जीईटी के साथ दिखाए जाते हैं) HttpResponseMessage या इस तरह कुछ नहीं लौटाते हैं।

+0

आप 'beta' उपयोग कर रहे हैं या * रात का निर्माण *? – Aliostad

+0

@Aliostad मैं बीटा – ozba

+0

का उपयोग कर रहा हूं तो 'नया HttpResponseMessage (HttpStatusCode.NotModified)' लौटने में क्या गलत है? क्या यह काम नहीं करता है? – Aliostad

उत्तर

186

मुझे जवाब नहीं पता था इसलिए एएसपी.NET टीम here से पूछा गया।

तो चाल हस्ताक्षर को HttpResponseMessage में बदलने और Request.CreateResponse का उपयोग करने के लिए है।

[ResponseType(typeof(User))] 
public HttpResponseMessage GetUser(HttpRequestMessage request, int userId, DateTime lastModifiedAtClient) 
{ 
    var user = new DataEntities().Users.First(p => p.Id == userId); 
    if (user.LastModified <= lastModifiedAtClient) 
    { 
     return new HttpResponseMessage(HttpStatusCode.NotModified); 
    } 
    return request.CreateResponse(HttpStatusCode.OK, user); 
} 
+2

यह एएसपी.नेट एमवीसी 4 बीटा रिलीज में संकलित नहीं है, क्योंकि CreateResponse केवल पैरामीटर के रूप में स्टेटस कोड लेता है। दूसरी बात यह है कि मैं बिना किसी HttpResponseMessage के समाधान के रूप में वापसी मान के रूप में एक समाधान चाहता था: http://aspnetwebstack.codeplex.com/discussions/350492 – ozba

+1

@ozba HttpResponseMessage को बहिष्कृत नहीं किया जा रहा है, ** सामान्य ** HttpResponseMessage है। मैंने यहां जेनेरिक का उपयोग नहीं किया है। – Aliostad

+0

यह अभी भी वेब एपीआई बीटा में संकलित नहीं है ... – ozba

58

अगर आपको लौटने उपयोगकर्ता के रूप में कार्रवाई हस्ताक्षर सुरक्षित रखना चाहते हैं निम्न कर सकते हैं:

public User GetUser(int userId, DateTime lastModifiedAtClient) 

आप 200 के अलावा कुछ वापस करना चाहते हैं तो आप फेंक अपनी कार्रवाई में एक HttpResponseException और HttpResponseMessage में आप ग्राहक को भेजना चाहते हैं।

+7

यह एक और अधिक सुरुचिपूर्ण समाधान (अल्बियट अधूरा उत्तर) है। हर कोई इसे कठिन तरीके से क्यों करना पसंद कर रहा है? – nagytech

+4

@Geoist http://stackoverflow.com/questions/1282252/कैसे-ज्यादा और अधिक महंगा है-एक-अपवाद tion से भी एक-रिटर्न-मूल्य। अपवाद फेंकना महंगा है। – tia

+8

हाँ, यदि आप एक व्यस्त एपीआई डिजाइन कर रहे हैं, तो 'NotModified' के सबसे आम मामले को संवाद करने के लिए अपवाद का उपयोग करना वास्तव में अपर्याप्त है। यदि आपके सभी एपीआई ने ऐसा किया है, तो आपका सर्वर ज्यादातर वाटों को अपवादों में परिवर्तित कर देगा। –

33

HttpResponseMessage को वापस करने के लिए GetXxx API विधि बदलें और फिर पूर्ण प्रतिक्रिया के लिए टाइप किए गए संस्करण और NotModified प्रतिक्रिया के लिए untyped संस्करण को वापस करें।

public HttpResponseMessage GetComputingDevice(string id) 
    { 
     ComputingDevice computingDevice = 
      _db.Devices.OfType<ComputingDevice>() 
       .SingleOrDefault(c => c.AssetId == id); 

     if (computingDevice == null) 
     { 
      return this.Request.CreateResponse(HttpStatusCode.NotFound); 
     } 

     if (this.Request.ClientHasStaleData(computingDevice.ModifiedDate)) 
     { 
      return this.Request.CreateResponse<ComputingDevice>(
       HttpStatusCode.OK, computingDevice); 
     } 
     else 
     { 
      return this.Request.CreateResponse(HttpStatusCode.NotModified); 
     } 
    } 

* क्लाइंटहासस्टेल डेटा ईटीएजी और IfModifiedSince शीर्षलेखों की जांच के लिए मेरा विस्तार है।

एमवीसी ढांचे को अभी भी क्रमबद्ध करना चाहिए और अपनी वस्तु वापस करनी चाहिए।

नोट

मैं जेनेरिक वर्जन वेब एपीआई के कुछ भविष्य संस्करण में हटाया जा रहा है लगता है।

+4

यह सही जवाब था जिसे मैं ढूंढ रहा था - यद्यपि एक कार्य > वापसी प्रकार के रूप में। धन्यवाद! – xeb

+1

@xeb - हाँ, यह पूरी तरह से कॉल करने लायक है। यहां एसिंक पर अधिक जानकारी http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4 –

27

MVC 5 में, चीज़ें आसान:

return new StatusCodeResult(HttpStatusCode.NotModified, this); 
+0

कोई संदेश निर्दिष्ट नहीं कर सकता है? – crush

+0

एक संदेश का उपयोग वास्तव में स्वीकार्य उत्तर है। यह सिर्फ थोड़ा सा है –

2
public HttpResponseMessage Post(Article article) 
{ 
    HttpResponseMessage response = Request.CreateResponse<Article>(HttpStatusCode.Created, article); 

    string uriToTheCreatedItem = Url.Route(null, new { id = article.Id }); 
    response.Headers.Location = new Uri(Request.RequestUri, uriToTheCreatedItem); 

    return response; 
} 
1

आप एक IHttpActionResult लौट सकते हैं और त्रुटि कोड के साथ साथ संदेश, उपयोग लौटना चाहते करने के लिए की जरूरत है:

return ResponseMessage(Request.CreateErrorResponse(HttpStatusCode.NotModified, "Error message here")); 
1

एक और विकल्प:

return new NotModified(); 

public class NotModified : IHttpActionResult 
{ 
    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken) 
    { 
     var response = new HttpResponseMessage(HttpStatusCode.NotModified); 
     return Task.FromResult(response); 
    } 
} 
1

मुझे HttpCreateResponse प्रकार का उपयोग करने के लिए अपना हस्ताक्षर बदलने की इच्छा नहीं है, इसलिए मैं इसे छुपाने के लिए एक विस्तारित समाधान के साथ आया।

public class HttpActionResult : IHttpActionResult 
{ 
    public HttpActionResult(HttpRequestMessage request) : this(request, HttpStatusCode.OK) 
    { 
    } 

    public HttpActionResult(HttpRequestMessage request, HttpStatusCode code) : this(request, code, null) 
    { 
    } 

    public HttpActionResult(HttpRequestMessage request, HttpStatusCode code, object result) 
    { 
     Request = request; 
     Code = code; 
     Result = result; 
    } 

    public HttpRequestMessage Request { get; } 
    public HttpStatusCode Code { get; } 
    public object Result { get; } 

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken) 
    { 
     return Task.FromResult(Request.CreateResponse(Code, Result)); 
    } 
} 

तब आप अपने ApiController के लिए एक विधि को जोड़ने (या अपने आधार नियंत्रक बेहतर) इस तरह कर सकते हैं:

protected IHttpActionResult CustomResult(HttpStatusCode code, object data) 
{ 
    // Request here is the property on the controller. 
    return new HttpActionResult(Request, code, data); 
} 

तो फिर तुम यह सिर्फ तरीकों में बनाया के किसी भी तरह वापस कर सकते हैं:

[HttpPost] 
public IHttpActionResult Post(Model model) 
{ 
    return model.Id == 1 ? 
       Ok() : 
       CustomResult(HttpStatusCode.NotAcceptable, new { 
        data = model, 
        error = "The ID needs to be 1." 
       }); 
} 
3

मुझे पुराने लेखों को बंपिंग से नफरत है, लेकिन Google खोज में इसका पहला परिणाम है और मुझे इस समस्या के साथ एक समय का एक बिल्ली था (यहां तक ​​कि आप लोगों के समर्थन के साथ)। तो यहां कुछ भी नहीं है ...

उम्मीद है कि मेरा समाधान उन लोगों की मदद करेगा जो भ्रमित भी थे।

namespace MyApplication.WebAPI.Controllers 
{ 
    public class BaseController : ApiController 
    { 
     public T SendResponse<T>(T response, HttpStatusCode statusCode = HttpStatusCode.OK) 
     { 
      if (statusCode != HttpStatusCode.OK) 
      { 
       // leave it up to microsoft to make this way more complicated than it needs to be 
       // seriously i used to be able to just set the status and leave it at that but nooo... now 
       // i need to throw an exception 
       var badResponse = 
        new HttpResponseMessage(statusCode) 
        { 
         Content = new StringContent(JsonConvert.SerializeObject(response), Encoding.UTF8, "application/json") 
        }; 

       throw new HttpResponseException(badResponse); 
      } 
      return response; 
     } 
    } 
} 

और फिर बस BaseController

[RoutePrefix("api/devicemanagement")] 
public class DeviceManagementController : BaseController 
{... 

से विरासत और फिर इसे का उपयोग कर

[HttpGet] 
[Route("device/search/{property}/{value}")] 
public SearchForDeviceResponse SearchForDevice(string property, string value) 
{ 
    //todo: limit search property here? 
    var response = new SearchForDeviceResponse(); 

    var results = _deviceManagementBusiness.SearchForDevices(property, value); 

    response.Success = true; 
    response.Data = results; 

    var statusCode = results == null || !results.Any() ? HttpStatusCode.NoContent : HttpStatusCode.OK; 

    return SendResponse(response, statusCode); 
} 
संबंधित मुद्दे