এএসপি.নেট ওয়েবএপিআই-তে কীভাবে কোনও ফাইল (ফাইলকন্টেন্টারসাল্ট) ফেরত পাবেন


173

একটি নিয়মিত এমভিসি নিয়ামক, আমরা একটি সঙ্গে পিডিএফ আউটপুট করতে পারেন FileContentResult

public FileContentResult Test(TestViewModel vm)
{
    var stream = new MemoryStream();
    //... add content to the stream.

    return File(stream.GetBuffer(), "application/pdf", "test.pdf");
}

তবে কীভাবে আমরা এটিকে পরিবর্তন করতে পারি ApiController?

[HttpPost]
public IHttpActionResult Test(TestViewModel vm)
{
     //...
     return Ok(pdfOutput);
}

এখানে আমি চেষ্টা করেছি কিন্তু এটি কাজ করে না বলে মনে হচ্ছে।

[HttpGet]
public IHttpActionResult Test()
{
    var stream = new MemoryStream();
    //...
    var content = new StreamContent(stream);
    content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
    content.Headers.ContentLength = stream.GetBuffer().Length;
    return Ok(content);            
}

ব্রাউজারে প্রদর্শিত ফলাফলটি হ'ল:

{"Headers":[{"Key":"Content-Type","Value":["application/pdf"]},{"Key":"Content-Length","Value":["152844"]}]}

এবং এসও তে একটি অনুরূপ পোস্ট রয়েছে: এএসপি.নেট ওয়েব এপিআই এ নিয়ন্ত্রক থেকে বাইনারি ফাইল ফিরছে । এটি একটি বিদ্যমান ফাইল আউটপুট সম্পর্কে কথা বলে। তবে আমি এটিকে কোনও স্ট্রিম দিয়ে কাজ করতে পারি না।

কোনও পরামর্শ?


1
এই পোস্টটি আমাকে সাহায্য করেছে: stackoverflow.com/a/23768883/585552
গ্রেগ

উত্তর:


199

StreamContentহিসাবে ফিরে আসার পরিবর্তে Content, আমি এটি দিয়ে কাজ করতে পারি ByteArrayContent

[HttpGet]
public HttpResponseMessage Generate()
{
    var stream = new MemoryStream();
    // processing the stream.

    var result = new HttpResponseMessage(HttpStatusCode.OK)
    {
        Content = new ByteArrayContent(stream.ToArray())
    };
    result.Content.Headers.ContentDisposition =
        new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
    {
        FileName = "CertificationCard.pdf"
    };
    result.Content.Headers.ContentType =
        new MediaTypeHeaderValue("application/octet-stream");

    return result;
}

2
যদি উপরের অর্ধেকটি আপনার প্রশ্নের উত্তর দেয় তবে দয়া করে কেবল উত্তর হিসাবে পোস্ট করুন। দ্বিতীয়ার্ধটি একটি আলাদা প্রশ্ন হিসাবে উপস্থিত হবে - এটির জন্য একটি নতুন প্রশ্ন পোস্ট করুন।
gunr2171

3
হাই, ভাগ করে নেওয়ার জন্য ধন্যবাদ, একটি সহজ প্রশ্ন পেয়েছে (আমার ধারণা)। আমার কাছে একটি সি # সামনের প্রান্ত রয়েছে যা httpresponsemessage প্রাপ্ত করে। আমি কীভাবে স্ট্রিম কনট্যাক্টটি বের করব এবং এটি উপলব্ধ করব যাতে কোনও ব্যবহারকারী এটি ডিস্ক বা কোনও কিছুতে সঞ্চয় করতে পারে (এবং আমি প্রকৃত ফাইলটি পেতে পারি)? ধন্যবাদ!
রোনাল্ড

7
আমি একটি স্ব উত্পন্ন এক্সেল ফাইল ডাউনলোড করার চেষ্টা করছিলাম। স্ট্রিম ব্যবহার করে.গেটব্ফার () সর্বদা একটি দূষিত এক্সেলকে ফিরিয়ে দেয়। পরিবর্তে যদি আমি স্ট্রিমটি ব্যবহার করি oToArray () ফাইলটি কোনও সমস্যা ছাড়াই উত্পন্ন। আশা করি এটি কাউকে সাহায্য করবে।
আফনেপায়ার

4
@ আলেকজান্দ্রপায়ার্স কারণ এটি MemoryStream.GetBuffer()আসলে মেমরিস্ট্রিমের বাফারটি দেয় যা সাধারণত স্ট্রিমের সামগ্রীর চেয়ে বড় থাকে (সন্নিবেশকে দক্ষ করতে)। MemoryStream.ToArray()সামগ্রী আকারে কাটা বাফারটি প্রদান করে।
এম স্ট্রামম

19
দয়া করে এটি করা বন্ধ করুন। মেমরিস্ট্রিমের এই ধরণের অপব্যবহারের কারণ, আনসকেবল কোড এবং স্ট্রিমের উদ্দেশ্যটিকে সম্পূর্ণ উপেক্ষা করে। চিন্তা করুন: কেন সবকিছু byte[]পরিবর্তে কেবল বাফার হিসাবে প্রকাশ করা হয় না? আপনার ব্যবহারকারীরা সহজেই মেমরির বাইরে আপনার অ্যাপ্লিকেশনটি চালাতে পারে।
মাখদুমী

97

আপনি যদি ফিরতে চান তবে আপনি এটি এইভাবে IHttpActionResultকরতে পারেন:

[HttpGet]
public IHttpActionResult Test()
{
    var stream = new MemoryStream();

    var result = new HttpResponseMessage(HttpStatusCode.OK)
    {
        Content = new ByteArrayContent(stream.GetBuffer())
    };
    result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
    {
        FileName = "test.pdf"
    };
    result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");

    var response = ResponseMessage(result);

    return response;
}

3
IHttpActionResult রিটার্নের ধরণটি দেখানোর জন্য ভাল আপডেট। : এই কোড একটি refactor যেমন এ তালিকাভুক্ত এক হিসাবে একটি কাস্টম IHttpActionResult কল সরাতে হবে stackoverflow.com/questions/23768596/...
জোশ

এই পোস্টটি একটি সুন্দর পরিপাটি করা একক ব্যবহারের বাস্তবায়ন দেখায়। আমার ক্ষেত্রে, উপরের লিঙ্কে তালিকাভুক্ত সহায়ক পদ্ধতি আরও সহায়ক হিসাবে প্রমাণিত হয়েছে
হাঞ্জোলো

45

এই প্রশ্নটি আমাকে সাহায্য করেছিল।

সুতরাং, এটি চেষ্টা করুন:

নিয়ামক কোড:

[HttpGet]
public HttpResponseMessage Test()
{
    var path = System.Web.HttpContext.Current.Server.MapPath("~/Content/test.docx");;
    HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
    var stream = new FileStream(path, FileMode.Open);
    result.Content = new StreamContent(stream);
    result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
    result.Content.Headers.ContentDisposition.FileName = Path.GetFileName(path);
    result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
    result.Content.Headers.ContentLength = stream.Length;
    return result;          
}

এইচটিএমএল মার্কআপ (ক্লিক ইভেন্ট এবং সাধারণ ইউআরএল সহ) দেখুন:

<script type="text/javascript">
    $(document).ready(function () {
        $("#btn").click(function () {
            // httproute = "" - using this to construct proper web api links.
            window.location.href = "@Url.Action("GetFile", "Data", new { httproute = "" })";
        });
    });
</script>


<button id="btn">
    Button text
</button>

<a href=" @Url.Action("GetFile", "Data", new { httproute = "" }) ">Data</a>

1
এখানে আপনি FileStreamসার্ভারে একটি বিদ্যমান ফাইলের জন্য ব্যবহার করছেন। এর থেকে কিছুটা আলাদা MemoryStream। কিন্তু ইনপুট জন্য ধন্যবাদ।
ব্লেইস

4
আপনি যদি কোনও ওয়েব সার্ভারের কোনও ফাইল থেকে পড়েন, তবে ফাইলশেয়ারের জন্য ওভারলোডটি ব্যবহার করতে ভুলবেন না e পড়ুন, অন্যথায় আপনি ব্যবহার ব্যাতিক্রমে ফাইলের মুখোমুখি হতে পারেন।
জেরেমি বেল

আপনি যদি মেমরি স্ট্রিমের সাথে এটি প্রতিস্থাপন করেন তবে এটি কার্যকর হবে না?
আলেহে

@ জেরেমিবেল এটি কেবল একটি সরল উদাহরণ, এখানে কেউ উত্পাদন এবং ব্যর্থ-নিরাপদ সংস্করণ সম্পর্কে কথা বলেন না।
আলেহে

1
@ ব্লাইজ এই কোডটি কেন কাজ করে FileStreamতবে এতে ব্যর্থ হয় তার জন্য নীচে দেখুন MemoryStream। এটি মূলত স্ট্রিমের সাথে করা উচিত Position
এম স্ট্রামম

9

এখানে এমন একটি প্রয়োগ রয়েছে যা ফাইলের সামগ্রীকে বাফার না করেই প্রবাহিত করে (বাইটে বাফার করা [] / মেমরিস্ট্রিম ইত্যাদি it's এটি কোনও বড় ফাইল হলে সার্ভারের সমস্যা হতে পারে)।

public class FileResult : IHttpActionResult
{
    public FileResult(string filePath)
    {
        if (filePath == null)
            throw new ArgumentNullException(nameof(filePath));

        FilePath = filePath;
    }

    public string FilePath { get; }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        var response = new HttpResponseMessage(HttpStatusCode.OK);
        response.Content = new StreamContent(File.OpenRead(FilePath));
        var contentType = MimeMapping.GetMimeMapping(Path.GetExtension(FilePath));
        response.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
        return Task.FromResult(response);
    }
}

এটি সহজেই এর মতো ব্যবহার করা যেতে পারে:

public class MyController : ApiController
{
    public IHttpActionResult Get()
    {
        string filePath = GetSomeValidFilePath();
        return new FileResult(filePath);
    }
}

ডাউনলোড শেষ হওয়ার পরে আপনি কীভাবে ফাইলটি মুছবেন? ডাউনলোড শেষ হয়ে গেলে কি কোনও হুককে অবহিত করতে হবে?
কস্টা

ঠিক আছে, উত্তরটি মনে হচ্ছে কোনও অ্যাকশন ফিল্টার বৈশিষ্ট্য প্রয়োগ করা হবে এবং অনএ্যাকশনএক্সেকিউটেড পদ্ধতিতে ফাইলটি সরিয়ে দেওয়া হবে।
কোস্টা

5
পোস্টটি Risord এর উত্তর খুঁজে পাওয়া যায়নি: stackoverflow.com/questions/2041717/... । যে কেউ এই লাইনটি ব্যবহার করতে পারেনvar fs = new FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.None, 4096, FileOptions.DeleteOnClose);File.OpenRead(FilePath)
a

7

কোন অংশটি দোষ দেবে আমি ঠিক তা নিশ্চিত নই, তবে এখানে কেন আপনার MemoryStreamপক্ষে কাজ করা হচ্ছে না:

আপনি যেমন লিখছেন MemoryStream, এটির Positionসম্পত্তি বৃদ্ধি করে । প্রস্ততকর্তার StreamContentএকাউন্টে স্ট্রীমের বর্তমান লাগে Position। সুতরাং আপনি যদি স্ট্রিমে লিখেন, তবে এটিকে প্রেরণ করুন StreamContent, প্রতিক্রিয়া স্ট্রিমের শেষের দিক থেকে নিরবতা থেকে শুরু হবে।

এটিকে যথাযথভাবে ঠিক করার দুটি উপায় রয়েছে:

1) সামগ্রী তৈরি করুন, প্রবাহে লিখুন

[HttpGet]
public HttpResponseMessage Test()
{
    var stream = new MemoryStream();
    var response = Request.CreateResponse(HttpStatusCode.OK);
    response.Content = new StreamContent(stream);
    // ...
    // stream.Write(...);
    // ...
    return response;
}

2) স্ট্রিম লিখুন, অবস্থান পুনরায় সেট করুন, সামগ্রী তৈরি করুন

[HttpGet]
public HttpResponseMessage Test()
{
    var stream = new MemoryStream();
    // ...
    // stream.Write(...);
    // ...
    stream.Position = 0;

    var response = Request.CreateResponse(HttpStatusCode.OK);
    response.Content = new StreamContent(stream);
    return response;
}

2) আপনার যদি নতুন স্রোত থাকে তবে কিছুটা ভাল দেখায়, 1) আপনার স্ট্রিম 0 থেকে শুরু না হলে সহজ is


এই কোডটি আসলে সমস্যার কোনও সমাধান সরবরাহ করে না, কারণ এটি একই পদ্ধতির ব্যবহার করে যা প্রশ্নটির উল্লেখ করা হয়েছিল। প্রশ্নটি ইতিমধ্যে জানিয়েছে যে এটি কাজ করে না, এবং আমি এটি নিশ্চিত করতে পারি। রিটার্ন ওকে (নতুন স্ট্রিম কনটেন্ট (স্ট্রিম)) স্ট্রিমকন্টের জেএসওএন প্রতিনিধিত্ব করে।
Dmytro Zhaharov

কোড আপডেট করেছে। এই উত্তরটি আসলে ওয়েবএপি-তে কোনও ফাইল কীভাবে ফিরে আসে তার চেয়ে 'সহজ সমাধানটি ফাইলস্ট্রিমে কাজ করে তবে মেমোরিস্ট্রিম নয়' এর আরও সূক্ষ্ম প্রশ্নের উত্তর দেয়।
এম স্ট্রামম

3

আমার জন্য এটি মধ্যে পার্থক্য ছিল

var response = Request.CreateResponse(HttpStatusCode.OK, new StringContent(log, System.Text.Encoding.UTF8, "application/octet-stream");

এবং

var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(log, System.Text.Encoding.UTF8, "application/octet-stream");

প্রথমটি স্ট্রিংকন্টের জেএসএন প্রতিনিধিত্ব ফিরিয়েছিল: {"শিরোলেখ": [Key "কী": "সামগ্রী-প্রকার", "মান": ["অ্যাপ্লিকেশন / অক্টেট-স্ট্রিম; চরসেট = utf-8"]}]}

দ্বিতীয়টি সঠিকভাবে ফাইলটি ফিরিয়ে দিচ্ছিল।

দেখে মনে হচ্ছে অনুরোধ.ক্রিয়েটরেসপনসের একটি ওভারলোড রয়েছে যা দ্বিতীয় প্যারামিটার হিসাবে স্ট্রিং নেয় এবং এটি স্ট্রিংকন্টেন্ট বস্তুটিকে প্রকৃত সামগ্রীর পরিবর্তে স্ট্রিং হিসাবে রেন্ডার করে চলেছে বলে মনে হয়।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.