वेब एपि कंट्रोलर से http स्टेटस कोड लौटना


219

मैं एक वेब एपीआई नियंत्रक में एक जीईटी विधि के लिए संशोधित नहीं 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;
    }
}

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


आप उपयोग कर रहे हैं betaया रात का निर्माण ?
एलियोस्टैड

@ अलीओस्ताद मैं बीटा का उपयोग कर रहा हूं
ओजबा

तो लौटने में क्या गलत है new HttpResponseMessage(HttpStatusCode.NotModified)? क्या यह काम नहीं करता है?
एलियोस्टैड

@Aliostad मैं HttpResponseMessage को वापस नहीं कर सकता, जब वापसी प्रकार उपयोगकर्ता है, यह संकलन नहीं है (स्पष्ट रूप से)।
ओजबा

जवाबों:


251

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

तो चाल को हस्ताक्षर को बदलने 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);
}

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

5
यदि किसी को इसकी आवश्यकता है, तो नियंत्रक विधि से मूल्य प्राप्त करना होगा GetUser(request, id, lastModified).TryGetContentValue(out user), जहां user(उदाहरण के मामले में) एक Userवस्तु है।
ग्रिन

4
क्या यह अभी भी 2015 में पसंदीदा तरीका है? MVC 5?
क्रश

4
अधिक आधुनिक संस्करण IHttpActionResult - HttpResponseMessage (2017)
niico

8
नीको के सुझाव में जोड़ने के लिए, जब वापसी प्रकार होता है IHttpActionResultऔर आप उपयोगकर्ता को वापस करना चाहते हैं, तो आप बस कर सकते हैं return Ok(user)। यदि आपको एक और स्थिति कोड (जैसे, निषिद्ध) वापस करने की आवश्यकता है तो आप बस कर सकते हैं return this.StatusCode(HttpStatusCode.Forbidden)
आकर्षित किया

68

यदि आप कार्रवाई हस्ताक्षर को संरक्षित करना चाहते हैं, तो आप निम्नलिखित कार्य भी कर सकते हैं:

public User GetUser(int userId, DateTime lastModifiedAtClient) 

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


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

4
@Geoist stackoverflow.com/questions/1282252/… । अपवाद फेंकना महंगा है।
tia

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

2
@nagytech क्योंकि आप एक त्रुटि त्रुटि संदेश वापस नहीं कर सकते हैं यदि आप एक त्रुटि (400 प्रतिक्रिया की तरह) फेंक देते हैं ... अपवाद भी फेंकना मूर्खतापूर्ण है कि आप कुछ करने की उम्मीद करते हैं। महँगा और तब लॉग किया जाएगा जब आप जानबूझकर उन्हें नहीं चाहते। वे वास्तव में अपवाद नहीं हैं।
रॉकलैन

40

MVC 5 में, चीजें आसान हो गईं:

return new StatusCodeResult(HttpStatusCode.NotModified, this);

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

1
संदेश का उपयोग करना वास्तव में स्वीकृत उत्तर है। यह सिर्फ एक छोटी सी बात है
जॉन बेट्स

39

HttpResponseMessage को वापस करने के लिए GetXxx API विधि को बदलें और फिर पूर्ण प्रतिक्रिया और NotModified प्रतिक्रिया के लिए अनछुए संस्करण के लिए एक टाइप किया हुआ संस्करण लौटाएँ।

    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);
        }
    }

* ClientHasStale डेटा ETag और IfModifiedSince हेडर की जाँच के लिए मेरा एक्सटेंशन है।

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

ध्यान दें

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


4
यह सटीक उत्तर था जिसकी मैं तलाश कर रहा था - यद्यपि एक टास्क <HttpResponseMessage <T >> रिटर्न प्रकार के रूप में। धन्यवाद!
xeb

1
@xeb - हाँ, यह पूरी तरह से कॉल करने के लायक है। Async पर अधिक जानकारी यहाँ asp.net/mvc/tutorials/mvc-4/…
ल्यूक पुप्लेट

14

मुझे पुराने लेखों से बहुत नफरत है, लेकिन 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;
        }
    }
}

और फिर बस बेसकंट्रोलर से विरासत में मिला

[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);
}

1
प्रतिभाशाली। मुझे एक टन समय बचा।
gls123

10

.net कोर 2.2 लौटकर 304 स्थिति कोड। यह एक ApiController का उपयोग कर रहा है।

    [HttpGet]
    public ActionResult<YOUROBJECT> Get()
    {
        return StatusCode(304);
    }

वैकल्पिक रूप से आप प्रतिक्रिया के साथ एक वस्तु वापस कर सकते हैं

    [HttpGet]
    public ActionResult<YOUROBJECT> Get()
    {
        return StatusCode(304, YOUROBJECT); 
    }

7

ASP.NET Web Api 2 के लिए, MS की यह पोस्ट विधि के रिटर्न प्रकार को बदलने का सुझाव देती है IHttpActionResult। इसके बाद आप में एक निर्मित लौट सकते हैं IHttpActionResultकी तरह कार्यान्वयन Ok, BadRequest, आदि ( यहाँ देखें ) या अपने खुद के कार्यान्वयन वापस जाएँ।

आपके कोड के लिए, यह किया जा सकता है:

public IHttpActionResult GetUser(int userId, DateTime lastModifiedAtClient)
{
    var user = new DataEntities().Users.First(p => p.Id == userId);
    if (user.LastModified <= lastModifiedAtClient)
    {
        return StatusCode(HttpStatusCode.NotModified);
    }
    return Ok(user);
}

3

एक अन्य विकल्प:

return new NotModified();

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

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;
}

2

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

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

2

मुझे 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." 
                });
}

0

IHttpActionResultWeb API 2 में शुरू किए गए अधिक मॉडन का उपयोग करके @Aliostads उत्तर का अपडेट ।

https://docs.microsoft.com/en-us/aspnet/web-api/overview/getting-started-with-aspnet-web-api/action-results#ihttpactionresult

public class TryController : ApiController
{
    public IHttpActionResult GetUser(int userId, DateTime lastModifiedAtClient)
    {
        var user = new DataEntities().Users.First(p => p.Id == userId);
        if (user.LastModified <= lastModifiedAtClient)
        {
            return StatusCode(HttpStatusCode.NotModified);
            // If you would like to return a Http Status code with any object instead:
            // return Content(HttpStatusCode.InternalServerError, "My Message");
        }
        return Ok(user);
    }
}

0

इसे इस्तेमाल करे :

return new ContentResult() { 
    StatusCode = 404, 
    Content = "Not found" 
};
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.