IAsyncEnumerable लौटना <टी> और Asp.Net कोर नियंत्रक से NotFound


10

नियंत्रक क्रिया के लिए सही हस्ताक्षर क्या है जो रिटर्न करता है IAsyncEnumerable<T>और NotFoundResultफिर भी एक async फैशन में संसाधित होता है?

मैंने इस हस्ताक्षर का उपयोग किया है और यह संकलन IAsyncEnumerable<T>योग्य नहीं है क्योंकि यह प्रतीक्षा योग्य नहीं है:

[HttpGet]
public async Task<IActionResult> GetAll(Guid id)
{
    try
    {
        return Ok(await repository.GetAll(id)); // GetAll() returns an IAsyncEnumerable
    }
    catch (NotFoundException e)
    {
        return NotFound(e.Message);
    }
}

यह ठीक संकलित करता है, लेकिन इसका हस्ताक्षर Async नहीं है। इसलिए मैं चिंतित हूं कि यह थ्रेड पूल धागे को अवरुद्ध करेगा या नहीं:

[HttpGet]
public IActionResult GetAll(Guid id)
{
    try
    {
        return Ok(repository.GetAll(id)); // GetAll() returns an IAsyncEnumerable
    }
    catch (NotFoundException e)
    {
        return NotFound(e.Message);
    }
}

मैंने await foreachइस तरह से एक लूप का उपयोग करने की कोशिश की लेकिन यह स्पष्ट रूप से या तो संकलित नहीं होगा:

[HttpGet]
public async IAsyncEnumerable<MyObject> GetAll(Guid id)
{
    IAsyncEnumerable<MyObject> objects;
    try
    {
        objects = contentDeliveryManagementService.GetAll(id); // GetAll() returns an IAsyncEnumerable
    }
    catch (DeviceNotFoundException e)
    {
        return NotFound(e.Message);
    }

    await foreach (var obj in objects)
    {
        yield return obj;
    }
}

5
आप MyObjectएक ही के साथ कई आइटम वापस कर रहे हैं id? आम तौर पर आप किसी NotFoundऐसी चीज़ के लिए नहीं भेजते हैं जो रिटर्न करती है IEnumerable- यह सिर्फ खाली होगी - या आप अनुरोधित id/ के साथ एकल आइटम लौटाएंगे NotFound
crgolden

1
IAsyncEnumerableप्रतीक्षित है। का उपयोग करें await foreach(var item from ThatMethodAsync()){...}
पनियागोटिस कानावोस

यदि आप वापस लौटना चाहते हैं IAsyncEnumerable<MyObject>, तो परिणाम को वापस करें, जैसे return objects। हालांकि यह HTTP एक्शन को स्ट्रीमिंग जीआरपीसी या सिग्नलआर विधि में परिवर्तित नहीं करेगा । मिडलवेयर अभी भी डेटा का उपभोग करेगा और क्लाइंट को एक ही HTTP रिस्पांस भेजेगा
पैनागोटिस कानावोस

विकल्प 2 ठीक है। ASP.NET Core प्लंबिंग एन्यूमरेशन का ध्यान रखता है और IAsyncEnumerable3.0 के रूप में अनभिज्ञ है।
कर्क लर्किन

धन्यवाद दोस्तों। मुझे पता है कि मैं यहां 404 नहीं लौटा हूं, लेकिन यह सिर्फ एक उदाहरण है। वास्तविक कोड काफी अलग है। @KirkLarkin एक कीट होने के लिए खेद है, लेकिन क्या आप 100% सुनिश्चित हैं कि इससे कोई अवरोध नहीं होगा? यदि हाँ, तो विकल्प 2 स्पष्ट समाधान है।
फ्रेडरिक द फ़ूल

जवाबों:


6

विकल्प 2, जिनमें से एक कार्यान्वयन गुजरता IAsyncEnumerable<>में Okकॉल, ठीक है। ASP.NET Core प्लंबिंग एन्यूमरेशन का ध्यान रखता है और IAsyncEnumerable<>3.0 के रूप में अनभिज्ञ है।

यहाँ प्रश्न से कॉल, संदर्भ के लिए दोहराया गया है:

return Ok(repository.GetAll(id)); // GetAll() returns an IAsyncEnumerable

कॉल का Okएक उदाहरण बनाता है OkObjectResult, जो विरासत में मिला है ObjectResult। करने के लिए भेजे गए मान Okप्रकार का है object, जो में आयोजित किया जाता ObjectResultहै Valueसंपत्ति। ASP.NET Core MVC कमांड पैटर्न का उपयोग करता है , जिसके द्वारा कमांड का कार्यान्वयन होता है IActionResultऔर क्रियान्वयन का उपयोग करके निष्पादित किया जाता है IActionResultExecutor<T>

के लिए ObjectResult, ObjectResultExecutorका उपयोग ObjectResultHTTP प्रतिक्रिया में बदलने के लिए किया जाता है । यह कार्यान्वयन की ObjectResultExecutor.ExecuteAsyncकि है IAsyncEnumerable<>-aware:

public virtual Task ExecuteAsync(ActionContext context, ObjectResult result)
{
    // ...

    var value = result.Value;

    if (value != null && _asyncEnumerableReaderFactory.TryGetReader(value.GetType(), out var reader))
    {
        return ExecuteAsyncEnumerable(context, result, value, reader);
    }

    return ExecuteAsyncCore(context, result, objectType, value);
}

जैसा कि कोड दिखाता है, Valueसंपत्ति को यह देखने के लिए जांचा जाता है कि क्या यह लागू होता है IAsyncEnumerable<>(विवरण कॉल में छिपा हुआ है TryGetReader)। यदि ऐसा होता है, तो उसे ExecuteAsyncEnumerableबुलाया जाता है, जो एन्यूमरेशन करता है और फिर एन्यूमरेटेड रिजल्ट को पास करता है ExecuteAsyncCore:

private async Task ExecuteAsyncEnumerable(ActionContext context, ObjectResult result, object asyncEnumerable, Func<object, Task<ICollection>> reader)
{
    Log.BufferingAsyncEnumerable(Logger, asyncEnumerable);

    var enumerated = await reader(asyncEnumerable);
    await ExecuteAsyncCore(context, result, enumerated.GetType(), enumerated);
}

readerउपरोक्त स्निपेट में वह स्थान है जहाँ पर संलयन होता है। यह थोड़ा दफन है, लेकिन आप यहां स्रोत देख सकते हैं :

private async Task<ICollection> ReadInternal<T>(object value)
{
    var asyncEnumerable = (IAsyncEnumerable<T>)value;
    var result = new List<T>();
    var count = 0;

    await foreach (var item in asyncEnumerable)
    {
        if (count++ >= _mvcOptions.MaxIAsyncEnumerableBufferLimit)
        {
            throw new InvalidOperationException(Resources.FormatObjectResultExecutor_MaxEnumerationExceeded(
                nameof(AsyncEnumerableReader),
                value.GetType()));
        }

        result.Add(item);
    }

    return result;
}

IAsyncEnumerable<>एक में प्रगणित है List<>का उपयोग करते हुए await foreach, जो लगभग परिभाषा के द्वारा, एक अनुरोध धागा ब्लॉक नहीं करता। जैसा कि Panagiotis Kanavos ने ओपी पर एक टिप्पणी में कहा था, इस गणना को ग्राहक को वापस भेजे जाने से पहले पूर्ण प्रदर्शन किया जाता है ।


विस्तृत उत्तर के लिए धन्यवाद Kirk :)। एक चिंता मुझे विकल्प 2 में एक्शन मेथड के साथ है। मुझे समझ में आया कि इसके रिटर्न वैल्यू को एसिंक्रोनस रूप से एन्यूमरेट किया जाएगा, लेकिन यह एक Taskऑब्जेक्ट को वापस नहीं करता है । क्या यह तथ्य स्वयं किसी भी तरह से अतुल्यकालिकता में बाधा डालता है? विशेष रूप से तुलना करें, कहें, एक समान विधि जो वापस आ गई Task
फ्रेडरिक द फ़ूल

1
नहीं, यह ठीक है। वहाँ लौटने का कोई कारण नहीं है Task, क्योंकि विधि स्वयं कोई भी अतुल्यकालिक कार्य नहीं करती है। यह अतुल्यकालिक है, जो ऊपर वर्णित के रूप में संभाला जाता है। आप देख सकते हैं कि Taskवहाँ का उपयोग किया जाता है, के निष्पादन में ObjectResult
कर्क लर्किन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.