ASP.Net MVC: วิธีแสดงอิมเมจอาร์เรย์ไบต์จากโมเดล


116

ฉันมีโมเดลที่มีไฟล์อิมเมจไบต์อาร์เรย์ที่ฉันต้องการแสดงบนเพจ

ฉันจะทำได้อย่างไรโดยไม่ต้องกลับไปที่ฐานข้อมูล

วิธีแก้ปัญหาทั้งหมดที่ฉันเห็นใช้ActionResultเพื่อกลับไปที่ฐานข้อมูลเพื่อดึงภาพ แต่ฉันมีภาพในโมเดลแล้ว ...


11
โปรดหยุดอ้างถึง "ASP.NET MVC" เพียงแค่เป็น "MVC" หนึ่งคือกรอบในขณะที่อีกแบบเป็นรูปแบบการออกแบบที่ไม่ขึ้นกับภาษา มันเหมือนกับการเรียก IE - "อินเทอร์เน็ต"
tereško

MVC จะแสดงอิมเมจอาร์เรย์ไบต์จากโมเดลเมื่อเป็นโมฆะได้อย่างไร
Chathz

คำตอบ:


214

สิ่งนี้อาจได้ผล ...

@{
    var base64 = Convert.ToBase64String(Model.ByteArray);
    var imgSrc = String.Format("data:image/gif;base64,{0}", base64);
}

<img src="@imgSrc" />

ดังที่ได้กล่าวไว้ในความคิดเห็นด้านล่างโปรดใช้ความรู้ข้างต้นซึ่งถึงแม้ว่าสิ่งนี้อาจตอบคำถามของคุณได้ แต่ก็อาจไม่สามารถแก้ปัญหาของคุณได้ ขึ้นอยู่กับปัญหาของคุณนี่อาจเป็นวิธีแก้ปัญหา แต่ฉันจะไม่แยกแยะการเข้าถึงฐานข้อมูลสองครั้งอย่างสมบูรณ์


6
ควรสังเกตว่าสิ่งนี้จะฝังรูปภาพใน HTML และจะหลีกเลี่ยงเทคนิคการแคชรูปภาพมาตรฐานต่างๆ
Quintin Robinson

@QuintinRobinson แม้ว่าจะลดจำนวนคำขอลง:)
dav_i

8
@dav_i ลดจำนวนคำขอเริ่มต้น เมื่อเพิ่มประสิทธิภาพเว็บเป็นสิ่งสำคัญอย่างยิ่งที่จะต้องเข้าใจกลไกของเซิร์ฟเวอร์แพลตฟอร์มเนื้อหาตัวกลางและไคลเอนต์ที่ร้องขอและประมวลผลข้อมูล ฉันไม่ต้องการลงรายละเอียดพิเศษในความคิดเห็น แต่ฉันต้องการเน้นย้ำว่าต้องเข้าใจผลของการใช้เทคนิคดังกล่าวอย่างแท้จริง
Quintin Robinson

1
คำตอบอาจถูกต้องสำหรับคำถาม แต่ฉันคิดว่าปัญหาที่เรากำลังพยายามแก้ไขนั้นมีข้อบกพร่อง หากปัญหาที่เกิดขึ้นคือการป้องกันไม่ให้มีการเรียกสองครั้งไปยังฐานข้อมูลเพื่อรับข้อมูลจากนั้นอีกหนึ่งวินาทีในการรับภาพฉันคิดว่าวิธีแก้ปัญหาที่ดีกว่าคือการใช้ตัวจัดการการจัดเรียงที่สามารถใช้แคชเพื่อลดภาระโดยรวมบนเซิร์ฟเวอร์ เมื่อคุณพยายามหาสาเหตุที่ทำให้แอปพลิเคชันของคุณสำลักเนื่องจากคุณกำลังพยายามทิ้งไฟล์ขนาดใหญ่โดยใช้การเข้ารหัส Base64 ไปยังสตรีมการตอบกลับของหน้าเว็บคุณจะหวังว่าคุณจะได้คิดมากขึ้นเกี่ยวกับภาพรวม
Nick Bork

2
เยี่ยมมากฉันได้เพิ่มวิธีการในโมเดลของฉันเพื่อที่จะใช้มันอีกครั้ง: สตริงสาธารณะ GetBase64 () {var base64 = Convert ToBase64String (ContentImage); ส่งคืน String.Format ("data: image / gif; base64, {0}", base64); }
Rodrigo Longo

40

สิ่งนี้ได้ผลสำหรับฉัน

<img src="data:image;base64,@System.Convert.ToBase64String(Model.CategoryPicture.Content)" width="80" height="80"/>     

1
อันนี้ใช้ได้ผลสำหรับฉันเช่นกันโปรดพูดว่าจะแสดงอิมเมจอาร์เรย์ไบต์จากโมเดลเมื่อเป็นโมฆะ
Chathz

สวัสดี Chathz ฉันขอแนะนำให้คุณตรวจสอบความถูกต้องของโมเดลในคอนโทรลเลอร์ก่อนที่จะส่งไปยังมุมมอง หากโมเดลเป็นโมฆะให้ส่งภาพเริ่มต้น
NoloMokgosi

26

ฉันขอแนะนำบางสิ่งตามบรรทัดเหล่านี้แม้ว่ารูปภาพจะอยู่ในตัวแบบของคุณก็ตาม

ฉันตระหนักดีว่าคุณกำลังขอวิธีเข้าถึงโดยตรงจากมุมมองและคนอื่น ๆ อีกมากมายได้ตอบและบอกคุณว่ามีอะไรผิดปกติกับวิธีการดังกล่าวดังนั้นนี่จึงเป็นอีกวิธีหนึ่งที่จะโหลดรูปภาพในแบบไม่ซิงค์สำหรับคุณและฉัน คิดว่าเป็นแนวทางที่ดีกว่า

แบบจำลองตัวอย่าง:

[Bind(Exclude = "ID")]
public class Item
{
    [Key]
    [ScaffoldColumn(false)]
    public int ID { get; set; }

    public String Name { get; set; }

    public byte[] InternalImage { get; set; } //Stored as byte array in the database.
}

วิธีการตัวอย่างในคอนโทรลเลอร์:

public async Task<ActionResult> RenderImage(int id)
{
    Item item = await db.Items.FindAsync(id);

    byte[] photoBack = item.InternalImage;

    return File(photoBack, "image/png");
}

ดู

@model YourNameSpace.Models.Item

@{
    ViewBag.Title = "Details";
}

<h2>Details</h2>

<div>
<h4>Item</h4>
<hr />
<dl class="dl-horizontal">
    <img src="@Url.Action("RenderImage", new { id = Model.ID})" />
</dl>
<dl class="dl-horizontal">
    <dt>
        @Html.DisplayNameFor(model => model.Name)
    </dt>

    <dd>
        @Html.DisplayFor(model => model.Name)
    </dd>
</dl>
</div>

2
"return File (... )" คืออะไร? ไฟล์ไม่ใช่คลาสแบบคงที่หรือไม่?
Ben Sewards

3
ควรเป็นวัตถุ FileContentResult ( msdn.microsoft.com/en-us/library/… )
Louie Bacaj

14

วิธีหนึ่งคือเพิ่มสิ่งนี้ลงในคลาส c # หรือคลาส HtmlExtensions ใหม่

public static class HtmlExtensions
{
    public static MvcHtmlString Image(this HtmlHelper html, byte[] image)
    {
        var img = String.Format("data:image/jpg;base64,{0}", Convert.ToBase64String(image));
        return new MvcHtmlString("<img src='" + img + "' />");
    }
}

จากนั้นคุณสามารถทำได้ในทุกมุมมอง

@Html.Image(Model.ImgBytes)

ฉันชอบสิ่งนี้มากที่สุด - ทำให้สะอาดใน Model และในไฟล์. cshtml GREAT !!
Ken

10

หากคุณสามารถเข้ารหัส base-64 ไบต์ของคุณคุณสามารถลองใช้ผลลัพธ์เป็นแหล่งรูปภาพของคุณ ในโมเดลของคุณคุณอาจเพิ่มสิ่งต่างๆเช่น:

public string ImageSource
{
    get
    {
        string mimeType = /* Get mime type somehow (e.g. "image/png") */;
        string base64 = Convert.ToBase64String(yourImageBytes);
        return string.Format("data:{0};base64,{1}", mimeType, base64);
    }
}

และในมุมมองของคุณ:

<img ... src="@Model.ImageSource" />

5

หากรูปภาพไม่ใหญ่ขนาดนั้นและหากมีโอกาสดีคุณจะนำรูปภาพกลับมาใช้บ่อยครั้งและหากคุณมีไม่มากเกินไปและหากรูปภาพไม่เป็นความลับ (หมายความว่ามันไม่ใหญ่ จัดการหากผู้ใช้รายหนึ่งอาจเห็นภาพของบุคคลอื่น) ...

"if" จำนวนมากที่นี่จึงเป็นโอกาสที่ดีที่จะเป็นความคิดที่ไม่ดี:

คุณสามารถจัดเก็บไบต์ของรูปภาพในCacheช่วงเวลาสั้น ๆ และทำให้แท็กรูปภาพชี้ไปที่วิธีการดำเนินการซึ่งจะอ่านจากแคชและคายรูปภาพของคุณออกมา วิธีนี้จะช่วยให้เบราว์เซอร์สามารถแคชรูปภาพได้อย่างเหมาะสม

// In your original controller action
HttpContext.Cache.Add("image-" + model.Id, model.ImageBytes, null,
    Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(1),
    CacheItemPriority.Normal, null);

// In your view:
<img src="@Url.Action("GetImage", "MyControllerName", new{fooId = Model.Id})">

// In your controller:
[OutputCache(VaryByParam = "fooId", Duration = 60)]
public ActionResult GetImage(int fooId) {
    // Make sure you check for null as appropriate, re-pull from DB, etc.
    return File((byte[])HttpContext.Cache["image-" + fooId], "image/gif");
}

สิ่งนี้มีประโยชน์เพิ่มเติม (หรือเป็นไม้ค้ำยัน?) ของการทำงานในเบราว์เซอร์รุ่นเก่าโดยที่ภาพอินไลน์ไม่ทำงานใน IE7 (หรือ IE8 หากมีขนาดใหญ่กว่า 32kB)


3

นี่คือคำตอบของ Manoj เวอร์ชันแก้ไขที่ฉันใช้กับโปรเจ็กต์ เพิ่งอัปเดตเพื่อรับคลาสแอตทริบิวต์ html และใช้ TagBuilder

    public static IHtmlString Image(this HtmlHelper helper, byte[] image, string imgclass, 
                                     object htmlAttributes = null)
    {
        var builder = new TagBuilder("img");
        builder.MergeAttribute("class", imgclass);
        builder.MergeAttributes(new RouteValueDictionary(htmlAttributes));

        var imageString = image != null ? Convert.ToBase64String(image) : "";
        var img = string.Format("data:image/jpg;base64,{0}", imageString);
        builder.MergeAttribute("src", img);

        return MvcHtmlString.Create(builder.ToString(TagRenderMode.SelfClosing));
    }

ซึ่งสามารถใช้งานได้แล้วดังนี้:

    @Html.Image(Model.Image, "img-cls", new { width="200", height="200" })

3

คุณต้องมีไบต์ [] ในฐานข้อมูลของคุณ

ไบต์ของฉัน [] อยู่ในวัตถุบุคคลของฉัน:

public class Person
{
    public byte[] Image { get; set; }
}


คุณต้องแปลงไบต์ [] ของคุณในสตริง ดังนั้นฉันมีในคอนโทรลเลอร์ของฉัน:

String img = Convert.ToBase64String(person.Image);


ถัดไปในไฟล์. cshtml ของฉัน Model ของฉันคือ ViewModel นี่คือสิ่งที่ฉันมีใน:

 public String Image { get; set; }


ฉันใช้แบบนี้ในไฟล์. cshtml ของฉัน:

<img src="@String.Format("data:image/jpg;base64,{0}", Model.Image)" />

"data: image / image file extension ; base64, {0}, your image String "

ฉันหวังว่ามันจะช่วยใครสักคน!


1

หากคุณต้องการนำเสนอรูปภาพให้เพิ่มเมธอดเป็นคลาสตัวช่วยหรือในโมเดลและอนุญาตให้เมธอดแปลงอิมเมจไบต์อาร์เรย์เป็นรูปแบบรูปภาพเช่น PNG หรือ JPG จากนั้นแปลงเป็นสตริง Base64 เมื่อคุณมีแล้วให้ผูกค่า base64 กับมุมมองของคุณในรูปแบบ

"data: image / [นามสกุลไฟล์รูปภาพ] ; base64, [สตริง base64 ของคุณอยู่ที่นี่] "

ข้างต้นถูกกำหนดให้กับแอตทริบิวต์imgของแท็กsrc

ปัญหาเดียวที่ฉันพบคือสตริง base64 ยาวเกินไป ดังนั้นฉันไม่แนะนำให้ใช้กับโมเดลหลาย ๆ แบบที่แสดงในมุมมอง


คุณทำให้เกิดปัญหาขึ้นและระบุสถานการณ์กรณีการใช้งานโดยไม่แนะนำ แต่ไม่มีวิธีแก้ไขสำหรับสถานการณ์กรณีการใช้งานของคุณ นั่นจะทำให้คำตอบของคุณดีขึ้น / มีประโยชน์และให้ข้อมูลมากขึ้น
Ken

0

ฉันได้สร้างวิธีการช่วยเหลือตามคำแนะนำด้านล่างและฉันดีใจมากที่ตัวช่วยนี้สามารถช่วยได้มากที่สุด

ด้วยแบบจำลอง:

 public class Images
 {
    [Key]
    public int ImagesId { get; set; }
    [DisplayName("Image")]
    public Byte[] Pic1 { get; set; }
  }

ผู้ช่วยคือ:

public static IHtmlString GetBytes<TModel, TValue>(this HtmlHelper<TModel> helper, System.Linq.Expressions.Expression<Func<TModel, TValue>> expression, byte[] array, string Id)
    {
        TagBuilder tb = new TagBuilder("img");
        tb.MergeAttribute("id", Id);
        var base64 = Convert.ToBase64String(array);
        var imgSrc = String.Format("data:image/gif;base64,{0}", base64);
        tb.MergeAttribute("src", imgSrc);
        return MvcHtmlString.Create(tb.ToString(TagRenderMode.SelfClosing));
    }

มุมมองกำลังรับวัตถุ: ICollection ดังนั้นคุณต้องใช้ในมุมมองในคำสั่ง foreach:

 @foreach (var item in Model)
  @Html.GetBytes(itemP1 => item.Pic1, item.Graphics, "Idtag")
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.