ASP.NET ওয়েব এপিআই এ নিয়ন্ত্রক থেকে বাইনারি ফাইল ফিরছে ing


323

আমি এএসপি.নেট এমভিসির নতুন ওয়েবএপিআই ব্যবহার করে একটি ওয়েব পরিষেবাতে কাজ করছি যা বাইনারি ফাইলগুলি, বেশিরভাগ .cabএবং .exeফাইলগুলি পরিবেশন করবে ।

নিম্নলিখিত কন্ট্রোলার পদ্ধতিটি কাজ করছে বলে মনে হচ্ছে এর অর্থ এটি কোনও ফাইল ফেরত দেয় তবে এটি সামগ্রীর ধরণটি এতে সেট করে application/json:

public HttpResponseMessage<Stream> Post(string version, string environment, string filetype)
{
    var path = @"C:\Temp\test.exe";
    var stream = new FileStream(path, FileMode.Open);
    return new HttpResponseMessage<Stream>(stream, new MediaTypeHeaderValue("application/octet-stream"));
}

এই কাজ করতে একটি ভাল উপায় আছে কি?


2
যে কেউ যদি ওয়েব এপিআই এবং আইএইচটিটিপিঅ্যাকশন রেজাল্টের মাধ্যমে স্ট্রিমের মাধ্যমে বাইট অ্যারে ফিরতে চাইছেন তবে এখানে দেখুন: নোডোগমাব্লগ.ব্রায়ানহোগান.ট.২০১7
ইব্রাহার মুমতাজ

উত্তর:


516

একটি সহজ ব্যবহার করার চেষ্টা করুন HttpResponseMessageতার সঙ্গে Contentএকটি থেকে সম্পত্তি সেট StreamContent:

// using System.IO;
// using System.Net.Http;
// using System.Net.Http.Headers;

public HttpResponseMessage Post(string version, string environment,
    string filetype)
{
    var path = @"C:\Temp\test.exe";
    HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
    var stream = new FileStream(path, FileMode.Open, FileAccess.Read);
    result.Content = new StreamContent(stream);
    result.Content.Headers.ContentType = 
        new MediaTypeHeaderValue("application/octet-stream");
    return result;
}

streamব্যবহৃত সম্পর্কে কয়েকটি বিষয় লক্ষণীয় :

  • আপনাকে অবশ্যই কল করতে হবে না stream.Dispose(), যেহেতু এটি যখন resultক্লায়েন্টের কাছে ডেটা ফেরত পাঠানোর নিয়ামক পদ্ধতির প্রক্রিয়া করে তখন ওয়েব এপিআই এর কাছে এটি অ্যাক্সেস করতে সক্ষম হওয়া দরকার । সুতরাং, একটি using (var stream = …)ব্লক ব্যবহার করবেন না । ওয়েব এপিআই আপনার জন্য স্ট্রিমটি নিষ্পত্তি করবে।

  • নিশ্চিত করুন যে স্ট্রিমটির বর্তমান অবস্থান 0 তে সেট করা আছে (অর্থাত স্ট্রিমের ডেটার সূচনা)। উপরের উদাহরণে, আপনি কেবলমাত্র ফাইলটি খোলার পরে এটি দেওয়া হয়েছে। তবে, অন্যান্য পরিস্থিতিতে (যেমন আপনি যখন প্রথমে কটিতে কিছু বাইনারি ডেটা লেখেন MemoryStream), নিশ্চিত stream.Seek(0, SeekOrigin.Begin);বা সেট করুনstream.Position = 0;

  • ফাইল স্ট্রিমগুলির সাথে, স্পষ্টরূপে নির্দিষ্টকরণের FileAccess.Readঅনুমতি ওয়েব সার্ভারগুলিতে অ্যাক্সেস রাইটস সমস্যাগুলি রোধ করতে সহায়তা করতে পারে; আইআইএস অ্যাপ্লিকেশন পুল অ্যাকাউন্টগুলি প্রায়শই কেবল পঠন / তালিকা / wwwroot- এ অ্যাক্সেস অধিকার সম্পাদন করে।


37
আপনি কি জানবেন কখন এই স্ট্রিমটি বন্ধ হয়ে যায়? আমি ধরে নিচ্ছি যে কাঠামোটি শেষ পর্যন্ত HttpResponseMessage.Dispose () কে কল করে, যার পরিবর্তে HttpResponseMessage.Content.Dispose () কলটি কার্যকরভাবে স্ট্রিমটি বন্ধ করে দেয়।
স্টিভ গুইদি

41
স্টিভ - আপনি সঠিক এবং আমি ফাইলস্ট্রিমে ব্রেকপয়েন্ট যুক্ত করে যাচাই করেছি is এই কোডটি টিপুন এবং চালিত করে। কাঠামোটি এইচটিটিপিআরস্পোনমেসেজ.ডিজপসকে কল করে, যা স্ট্রিমকন্টেন্ট.ডিজপসকে কল করে যা ফাইলস্ট্রিম.ডিসপোজকে কল করে।
ড্যান গার্টনার

15
আপনি usingফলাফল ( HttpResponseMessage) বা স্ট্রিম নিজেই কোনওটিতে যুক্ত করতে পারবেন না কারণ এগুলি এখনও পদ্ধতির বাইরে ব্যবহার করা হবে। @ ড্যান যেমন উল্লেখ করেছেন, ক্লায়েন্টের প্রতিক্রিয়া পাঠানোর পরে ফ্রেমওয়ার্কটি তারা নিষ্পত্তি করে দেবে।
কার্লোসফিগুইরা

2
@ বি ক্লেশ্যানন হ্যাঁ, এটি প্রায়। যতক্ষণ ক্লায়েন্টের সাথে সম্পর্কিত তবে এটি এইচটিটিপি প্রতিক্রিয়াটির বিষয়বস্তুতে কেবল একগুচ্ছ বাইট। স্থানীয় ফাইলে সেভ করা সহ ক্লায়েন্ট সেই বাইটগুলি যা কিছু চয়ন করে তা করতে পারে।
carlosfigueira

5
@ কার্লোসফিগুইরা, হাই, বাইটস সব প্রেরণের পরে কীভাবে ফাইলটি মুছতে হয় তা আপনি জানেন?
Zach

137

জন্য ওয়েব এপিআই 2 , আপনি বাস্তবায়ন করতে পারেন IHttpActionResult। এখানে আমার:

using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;

class FileResult : IHttpActionResult
{
    private readonly string _filePath;
    private readonly string _contentType;

    public FileResult(string filePath, string contentType = null)
    {
        if (filePath == null) throw new ArgumentNullException("filePath");

        _filePath = filePath;
        _contentType = contentType;
    }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        var response = new HttpResponseMessage(HttpStatusCode.OK)
        {
            Content = new StreamContent(File.OpenRead(_filePath))
        };

        var contentType = _contentType ?? MimeMapping.GetMimeMapping(Path.GetExtension(_filePath));
        response.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);

        return Task.FromResult(response);
    }
}

তারপরে আপনার নিয়ামকের মধ্যে এরকম কিছু:

[Route("Images/{*imagePath}")]
public IHttpActionResult GetImage(string imagePath)
{
    var serverPath = Path.Combine(_rootPath, imagePath);
    var fileInfo = new FileInfo(serverPath);

    return !fileInfo.Exists
        ? (IHttpActionResult) NotFound()
        : new FileResult(fileInfo.FullName);
}

এবং এখানে একটি উপায় আপনি আইআইএসকে একটি বর্ধনের সাথে অনুরোধগুলি উপেক্ষা করতে বলতে পারেন যাতে অনুরোধটি এটি নিয়ামকের কাছে করতে পারে:

<!-- web.config -->
<system.webServer>
  <modules runAllManagedModulesForAllRequests="true"/>

1
সুন্দর উত্তর, সর্বদা এসও কোড ঠিক পেস্ট করার পরে এবং বিভিন্ন ক্ষেত্রে (বিভিন্ন ফাইল) চালিত হয় না।
Krzysztof Morcinek

1
ধন্যবাদ জনিএডামিট আমার মনে হয় অন্য বিকল্পটি হ'ল asyncপদ্ধতি স্বাক্ষরে একটি সংশোধক স্থাপন করা এবং একটি কার্য সম্পূর্ণরূপে সরিয়ে ফেলা: gist.github.com/ronnieoverby/ae0982c7832c531a9022
রনি ওভারবি

4
এই চলমান আইআইএস ++ এর উপরে যে কেউ আসবে তার জন্য কেবল একটি মাথা। রানআল ম্যানেজডমডিউলস ফরআররেখেসস এখন বাদ দেওয়া যাবে
সূচক

1
@ বেনডেগ মনে হয় একসময় আমি উত্সটি পরীক্ষা করেছিলাম এবং এটি করেছিল। এবং এটি বোঝা যায় যে এটি করা উচিত। কাঠামোর উত্সটি নিয়ন্ত্রণ করতে সক্ষম না হওয়া, এই প্রশ্নের কোনও উত্তর সময়ের সাথে পরিবর্তিত হতে পারে।
রনি ওভারবি

1
ইতিমধ্যে ফাইলআরসাল্ট (এবং এমনকি ফাইল স্ট্রিম রিসাল্ট) শ্রেণিতে একটি বিল্ট রয়েছে।
BrainSlugs83

12

NET কোর ব্যবহার করে তাদের জন্য:

আপনি এআইপিআই নিয়ন্ত্রক পদ্ধতিতে IActionResult ইন্টারফেসটি ব্যবহার করতে পারেন, এর মতো ...

    [HttpGet("GetReportData/{year}")]
    public async Task<IActionResult> GetReportData(int year)
    {
        // Render Excel document in memory and return as Byte[]
        Byte[] file = await this._reportDao.RenderReportAsExcel(year);

        return File(file, "application/vnd.openxmlformats", "fileName.xlsx");
    }

এই উদাহরণটি সরল করা হয়েছে তবে পয়েন্টটি পাওয়া উচিত। .NET কোর এই প্রক্রিয়া তাই অনেক .NET পূর্ববর্তী সংস্করণে উপস্থিত চেয়ে সহজ - অর্থাৎ যদি কোনো সেটিং প্রতিক্রিয়া ধরন, বিষয়বস্তু, হেডার, ইত্যাদি

এছাড়াও, অবশ্যই ফাইলটির জন্য মাইম টাইপ এবং এক্সটেনশনটি পৃথক প্রয়োজনের উপর নির্ভর করবে।

তথ্যসূত্র: @ এনকোসির দ্বারা এসও পোস্টের উত্তর


1
কেবলমাত্র একটি নোট, যদি এটি কোনও চিত্র হয় এবং আপনি এটি সরাসরি URL টি অ্যাক্সেস সহ কোনও ব্রাউজারে দেখতে পারাতে চান তবে কোনও ফাইলের নাম সরবরাহ করবেন না।
প্লুটো

9

প্রস্তাবিত সমাধানটি ঠিকঠাক কাজ করার সময়, নিয়ন্ত্রকের কাছ থেকে বাইট অ্যারে ফেরত দেওয়ার আরও একটি উপায় রয়েছে, প্রতিক্রিয়া প্রবাহটি সঠিকভাবে ফর্ম্যাট করা সহ:

  • অনুরোধে, শিরোনাম সেট করুন "স্বীকার করুন: অ্যাপ্লিকেশন / অক্টেট স্ট্রিম"।
  • সার্ভার-সাইড, এই মাইম প্রকারটি সমর্থন করতে একটি মিডিয়া টাইপ ফর্ম্যাটর যুক্ত করুন।

দুর্ভাগ্যক্রমে, ওয়েবএপি "অ্যাপ্লিকেশন / অক্টেট-স্ট্রিম" এর জন্য কোনও ফর্ম্যাটর অন্তর্ভুক্ত করে না। গীটহাবটিতে এখানে একটি বাস্তবায়ন রয়েছে: বাইনারিমিডিয়া টাইপ ফর্ম্যাটার (এটি ওয়েবপি 2 এর জন্য কাজ করার জন্য ছোটখাটো অভিযোজন রয়েছে, পদ্ধতিতে স্বাক্ষর পরিবর্তিত হয়েছে)।

আপনি এই গ্লোবাল কনফিগারেশনে এই ফর্ম্যাটরটি যুক্ত করতে পারেন:

HttpConfiguration config;
// ...
config.Formatters.Add(new BinaryMediaTypeFormatter(false));

BinaryMediaTypeFormatterঅনুরোধটি সঠিক গ্রহণ করুন শিরোনাম নির্দিষ্ট করে থাকলে এখন ওয়েবএপি ব্যবহার করা উচিত ।

আমি এই সমাধানটি পছন্দ করি কারণ কোনও অ্যাকশন কন্ট্রোলার বাইট প্রত্যাবর্তন [] পরীক্ষা করা আরও স্বাচ্ছন্দ্যযুক্ত। যদিও, আপনি যদি "অ্যাপ্লিকেশন / অক্টেট-স্ট্রিম" (উদাহরণস্বরূপ "চিত্র / জিআইএফ") এর চেয়ে অন্য সামগ্রী-টাইপ করতে চান তবে অন্য সমাধান আপনাকে আরও নিয়ন্ত্রণের অনুমতি দেয়।


8

গ্রহণযোগ্য উত্তরে পদ্ধতিটি ব্যবহার করে মোটামুটি বড় ফাইল ডাউনলোড করার সময় যে কোনও ব্যক্তির এপিআইয়ের সমস্যাটি একবারে একাধিকবার ডেকে আনা হয়েছে, দয়া করে প্রতিক্রিয়া বাফারিংটি সত্য সিস্টেমে সেট করুন e ওয়েব.এইচটিটিপেক্সটেক্সট.ক্রন্ট.রেস্পোনস.বফার = সত্য;

এটি নিশ্চিত করে যে ক্লায়েন্টকে প্রেরণের আগে পুরো বাইনারি সামগ্রীটি সার্ভারের পাশেই বাফার হয়েছে। অন্যথায় আপনি নিয়ন্ত্রণকারীর কাছে একাধিক অনুরোধ প্রেরণ করতে দেখবেন এবং আপনি যদি এটি সঠিকভাবে পরিচালনা না করেন তবে ফাইলটি দুর্নীতিগ্রস্থ হয়ে যাবে।


3
Bufferসম্পত্তি অবচিত হয়েছে পক্ষে BufferOutput। এটি ডিফল্ট true

6

আপনি যে ওভারলোডটি ব্যবহার করছেন সেটি সিরিয়ালাইজেশন ফর্ম্যাটারগুলির তালিকা নির্ধারণ করে। আপনার সামগ্রীর ধরণটি স্পষ্টভাবে উল্লেখ করতে হবে:

httpResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");

3
জবাবের জন্য ধন্যবাদ. আমি এটি চেষ্টা করে দেখেছি এবং আমি এখনও Content Type: application/jsonফিডলারের মধ্যে দেখতে পাচ্ছি । Content Typeযদি আমি ফেরার আগে ভঙ্গ সঠিকভাবে সেট করছে বলে মনে হচ্ছে httpResponseMessageপ্রতিক্রিয়া। আর কোন ধারণা?
জোশ আর্ল

3

আপনি চেষ্টা করতে পারেন

httpResponseMessage.Content.Headers.Add("Content-Type", "application/octet-stream");
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.