asp.net-mvc custom - هل تستطيع وحدة تحكم ASP.NET MVC عرض صورة؟



validation c# (14)

هل يمكنني إنشاء وحدة تحكم تقوم فقط بإرجاع أصل الصورة؟

أود توجيه هذا المنطق من خلال جهاز تحكم ، كلما طلب عنوان URL مثل ما يلي:

www.mywebsite.com/resource/image/topbanner

سوف تبحث وحدة التحكم عن topbanner.png وترسل تلك الصورة مباشرة إلى العميل.

لقد رأيت أمثلة على ذلك حيث يجب عليك إنشاء عرض - لا أريد استخدام طريقة عرض. أريد أن أفعل كل ذلك فقط مع المراقب المالي.

هل هذا ممكن؟


Answers

هذا العمل بالنسبة لي. منذ أنا تخزين الصور على قاعدة بيانات SQL Server.

    [HttpGet("/image/{uuid}")]
    public IActionResult GetImageFile(string uuid) {
        ActionResult actionResult = new NotFoundResult();
        var fileImage = _db.ImageFiles.Find(uuid);
        if (fileImage != null) {
            actionResult = new FileContentResult(fileImage.Data,
                fileImage.ContentType);
        }
        return actionResult;
    }

في المقتطف أعلاه _db.ImageFiles.Find(uuid) تبحث عن سجل ملف الصورة في db (سياق EF). تقوم بإرجاع كائن FileImage الذي يعد فقط فئة مخصصة قمت بعملها للنموذج ثم يستخدمه كـ FileContentResult.

public class FileImage {
   public string Uuid { get; set; }
   public byte[] Data { get; set; }
   public string ContentType { get; set; }
}

استكمال: هناك خيارات أفضل من جوابي الأصلي. هذا يعمل خارج MVC بشكل جيد ولكن من الأفضل الالتزام بالأساليب المضمنة لإعادة محتوى الصورة. الاطلاع على الإجابات صعودًا.

يمكنك بالتأكيد. جرب هذه الخطوات:

  1. قم بتحميل الصورة من القرص إلى صفيف بايت
  2. تخزين الصورة في الحالة التي تتوقع فيها المزيد من الطلبات للصورة ولا تريد إدخال / إخراج القرص (لا تخزن العينة مؤقتًا أدناه)
  3. قم بتغيير نوع mime عبر Response.ContentType
  4. Response.BinaryWrite خارج مجموعة بايت الصورة

إليك بعض نماذج التعليمة البرمجية:

string pathToFile = @"C:\Documents and Settings\some_path.jpg";
byte[] imageData = File.ReadAllBytes(pathToFile);
Response.ContentType = "image/jpg";
Response.BinaryWrite(imageData);

امل ان يساعد!


يمكنك استخدام File لإرجاع ملف مثل View، Content etc

 public ActionResult PrintDocInfo(string Attachment)
            {
                string test = Attachment;
                if (test != string.Empty || test != "" || test != null)
                {
                    string filename = Attachment.Split('\\').Last();
                    string filepath = Attachment;
                    byte[] filedata = System.IO.File.ReadAllBytes(Attachment);
                    string contentType = MimeMapping.GetMimeMapping(Attachment);

                    System.Net.Mime.ContentDisposition cd = new System.Net.Mime.ContentDisposition
                    {
                        FileName = filename,
                        Inline = true,
                    };

                    Response.AppendHeader("Content-Disposition", cd.ToString());

                    return File(filedata, contentType);          
                }
                else { return Content("<h3> Patient Clinical Document Not Uploaded</h3>"); }

            }

استخدم أسلوب "التحكم الأساسي" في الملفات.

public ActionResult Image(string id)
{
    var dir = Server.MapPath("/Images");
    var path = Path.Combine(dir, id + ".jpg"); //validate the path for security or use other means to generate the path.
    return base.File(path, "image/jpeg");
}

كملاحظة ، يبدو أن هذا فعال إلى حد ما. لقد أجريت اختبارًا حيث طلبت الصورة من خلال وحدة التحكم ( http://localhost/MyController/Image/MyImage ) وعبر عنوان URL المباشر ( http://localhost/Images/MyImage.jpg ) وكانت النتائج:

  • MVC: 7.6 ميلي ثانية لكل صورة
  • Direct: 6.7 مللي ثانية لكل صورة

ملاحظة: هذا هو متوسط ​​وقت الطلب. تم حساب المتوسط ​​عن طريق جعل الآلاف من الطلبات على الجهاز المحلي ، لذلك لا يجب أن تتضمن الإجماليات وقت استجابة الشبكة أو مشكلة عرض النطاق الترددي.


لماذا لا تذهب بسيطة واستخدام المشغل تيلدا ~ ؟

public FileResult TopBanner() {
  return File("~/Content/images/topbanner.png", "image/png");
}

لفضاء على استجابة Dyland قليلا:

ثلاث فئات تطبيق فئة FileResult :

System.Web.Mvc.FileResult
      System.Web.Mvc.FileContentResult
      System.Web.Mvc.FilePathResult
      System.Web.Mvc.FileStreamResult

انهم جميعا تفسيرية النفس إلى حد ما:

  • بالنسبة لتنزيلات مسار الملفات حيث يوجد الملف على القرص ، استخدم FilePathResult - هذه هي الطريقة الأسهل وتجنب استخدام تيارات.
  • للحصول على صفيف [] بايت [أقرب إلى Response.BinaryWrite) ، استخدم FileContentResult .
  • بالنسبة إلى صفيفات البايت [] حيث تريد تنزيل الملف (content-disposition: attachment) ، استخدم FileStreamResult بالطريقة نفسها أدناه ، ولكن باستخدام MemoryStream واستخدام GetBuffer() .
  • Streams استخدام FileStreamResult . يطلق عليه FileStreamResult لكنه يأخذ Stream لذلك أعتقد أنه يعمل مع MemoryStream .

فيما يلي مثال على استخدام تقنية تصرف المحتوى (لم يتم اختبارها):

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult GetFile()
    {
        // No need to dispose the stream, MVC does it for you
        string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "App_Data", "myimage.png");
        FileStream stream = new FileStream(path, FileMode.Open);
        FileStreamResult result = new FileStreamResult(stream, "image/png");
        result.FileDownloadName = "image.png";
        return result;
    }

if (!System.IO.File.Exists(filePath))
    return SomeHelper.EmptyImageResult(); // preventing JSON GET/POST exception
else
    return new FilePathResult(filePath, contentType);

يجب أن ترجع SomeHelper.EmptyImageResult() FileResult مع الصورة الموجودة (1 × 1 شفاف ، على سبيل المثال).

هذه أسهل طريقة إذا كان لديك ملفات مخزنة على محرك أقراص محلي. إذا كانت الملفات byte[] أو stream - ثم استخدم FileContentResult أو FileStreamResult كما اقترح ديلان.


باستخدام نسخة إصدار MVC ، إليك ما أقوم به:

[AcceptVerbs(HttpVerbs.Get)]
[OutputCache(CacheProfile = "CustomerImages")]
public FileResult Show(int customerId, string imageName)
{
    var path = string.Concat(ConfigData.ImagesDirectory, customerId, "\\", imageName);
    return new FileStreamResult(new FileStream(path, FileMode.Open), "image/jpeg");
}

من الواضح أن لدي بعض الأشياء الخاصة بالتطبيق هنا فيما يتعلق ببناء المسار ، ولكن إرجاع FileStreamResult هو أمر لطيف وبسيط.

أجريت بعض اختبارات الأداء فيما يتعلق بهذا الإجراء ضد مكالمتك اليومية للصورة (تجاوز جهاز التحكم) وكان الفرق بين المتوسطات حوالي 3 مللي ثانية فقط (كان متوسط ​​وحدة التحكم 68 مللي ثانية ، وكان جهاز التحكم غير 65 مللي ثانية).

لقد جربت بعض الطرق الأخرى المذكورة في الإجابات هنا وكان أداءها أكثر دراماتيكية ... العديد من استجابات الحلول كانت بقدر 6x غير المتحكم (وحدات التحكم الأخرى avg 340ms ، 65-x غير تحكم).


يمكنك استخدام HttpContext.Response وكتابة المحتوى مباشرة (قد يعمل WriteFile () لك ثم) وإرجاع ContentResult من الإجراء الخاص بك بدلاً من ActionResult.

إخلاء المسؤولية: لم أحاول ذلك ، لأنه يعتمد على النظر إلى واجهات برمجة التطبيقات المتاحة. :-)


قد يكون هذا مفيدًا إذا كنت تريد تعديل الصورة قبل إعادتها:

public ActionResult GetModifiedImage()
{
    Image image = Image.FromFile(Path.Combine(Server.MapPath("/Content/images"), "image.png"));

    using (Graphics g = Graphics.FromImage(image))
    {
        // do something with the Graphics (eg. write "Hello World!")
        string text = "Hello World!";

        // Create font and brush.
        Font drawFont = new Font("Arial", 10);
        SolidBrush drawBrush = new SolidBrush(Color.Black);

        // Create point for upper-left corner of drawing.
        PointF stringPoint = new PointF(0, 0);

        g.DrawString(text, drawFont, drawBrush, stringPoint);
    }

    MemoryStream ms = new MemoryStream();

    image.Save(ms, System.Drawing.Imaging.ImageFormat.Png);

    return File(ms.ToArray(), "image/png");
}

انظر إلى ContentResult. هذا إرجاع سلسلة ولكن يمكن استخدامها لإنشاء فئة تشبه BinaryResult الخاصة بك.



أرى خيارين:

1) تنفيذ IViewEngine الخاصة بك وتعيين الخاصية ViewEngine من وحدة تحكم كنت تستخدم ل ImageViewEngine الخاص بك في طريقة "صورة" المطلوب.

2) استخدم طريقة العرض :-). ما عليك سوى تغيير نوع المحتوى وما إلى ذلك.


كيف لي الألغام إلى حد كبير على النحو الوارد أعلاه سوء تظهر لك الكود الخاص بي وكيفية استخدامه مع DB MYSSQL ...

جدول المستند في DB -

int id (PK) ، سلسلة Url ، سلسلة الوصف ، CreatedBy ، TenancyId DateUploaded

معرف الكود أعلاه ، كونه المفتاح الأساسي ، عنوان URL هو اسم الملف (مع نوع الملف في النهاية) ، وصف الملف إلى ouput في عرض المستندات ، CreatedBy الذي قام بتحميل الملف ، tenancyId ، dateUploaded

داخل العرض يجب عليك تعريف enctype أو أنها لن تعمل بشكل صحيح.

@using (Html.BeginForm("Upload", "Document", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="input-group">
    <label for="file">Upload a document:</label>
    <input type="file" name="file" id="file" />
</div>
}

سيعطيك الكود السابق زر التصفح ، ثم داخل مشروعي لدي فئة تسمى أساسًا IsValidImage والتي تقوم فقط بالتحقق من حجم الملف تحت الحد الأقصى المحدد ، ويتحقق مما إذا كان ملف IMG الخاص به ، هذا كله في وظيفة bool class. لذلك إذا عاد صحيح صحيح.

public static bool IsValidImage(HttpPostedFileBase file, double maxFileSize, ModelState ms )
{
    // make sur the file isnt null.
    if( file == null )
        return false;

// the param I normally set maxFileSize is 10MB  10 * 1024 * 1024 = 10485760 bytes converted is 10mb
var max = maxFileSize * 1024 * 1024;

// check if the filesize is above our defined MAX size.
if( file.ContentLength > max )
    return false;

try
{
    // define our allowed image formats
    var allowedFormats = new[] { ImageFormat.Jpeg, ImageFormat.Png, ImageFormat.Gif, ImageFormat.Bmp };

    // Creates an Image from the specified data stream.      
    using (var img = Image.FromStream(file.InputStream))
    {
        // Return true if the image format is allowed
        return allowedFormats.Contains(img.RawFormat);
    }
}
catch( Exception ex )
{
    ms.AddModelError( "", ex.Message );                 
}
return false;   
}

حتى في وحدة تحكم:

if (!Code.Picture.IsValidUpload(model.File, 10, true))
{                
    return View(model);
}

// Set the file name up... Being random guid, and then todays time in ticks. Then add the file extension
// to the end of the file name
var dbPath = Guid.NewGuid().ToString() + DateTime.UtcNow.Ticks + Path.GetExtension(model.File.FileName);

// Combine the two paths together being the location on the server to store it
// then the actual file name and extension.
var path = Path.Combine(Server.MapPath("~/Uploads/Documents/"), dbPath);

// set variable as Parent directory I do this to make sure the path exists if not
// I will create the directory.
var directoryInfo = new FileInfo(path).Directory;

if (directoryInfo != null)
    directoryInfo.Create();

// save the document in the combined path.
model.File.SaveAs(path);

// then add the data to the database
_db.Documents.Add(new Document
{
    TenancyId = model.SelectedTenancy,
    FileUrl = dbPath,
    FileDescription = model.Description,
    CreatedBy = loggedInAs,
    CreatedDate = DateTime.UtcNow,
    UpdatedDate = null,
    CanTenantView = true
});

_db.SaveChanges();
model.Successfull = true;




asp.net asp.net-mvc image controller