从MVC控制器返回内联动态SVG



我正在我的控制器上构建一个方法来生成SVG QR代码(QRCoder(,并且我正在尝试使用控制器上的方法将生成的SVG从控制器内联到视图中。

当我尝试直接查看该方法时,我看到SVG XML成功返回,但它出现了异常。我不太确定我需要什么才能让我的控制器返回,这样我就可以在我的视野中做到这一点。

<img src="~/Redirect/QRCode/{code}/svg"/>

等效的PNG版本可以完美地工作。

<img src="~/Redirect/QRCode/{code}/png"/>
[Route("[controller]/QRCode/{code}/{format?}")]
public IActionResult QRCodeImage(string code, BarcodeService.Format format = BarcodeService.Format.Png)
{
//Database call to get the real Uri...
var uri = "https://github.com/paulfarry/";
switch (format)
{
case BarcodeService.Format.Svg:
{
var data = barcodeService.GenerateQRCodeSvg(uri);
return File(data, "image/svg+xml; charset=utf-8");
}
case BarcodeService.Format.Png:
default:
{
var data = barcodeService.GenerateQRCode(uri);
return File(data, "image/png");
}
}
}

当我直接查看页面时,我本希望看到呈现的SVG,但我得到了这个异常信息和SVG数据。

https://localhost:5001/Redirect/QRCode/a/svg
An unhandled exception occurred while processing the request.
FileNotFoundException: Could not find file: 
<svg version="1.1" baseProfile="full" shape-rendering="crispEdges" width="740" height="740" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><rect x="0" y="0" width="740" height="740" fill="#FFFFFF" />
<!--Remaining SVG data is here-->
</svg>

Microsoft.AspNetCore.Mvc.Infrastructure.VirtualFileResultExecutor.ExecuteAsync(ActionContext context, VirtualFileResult result)
Microsoft.AspNetCore.Mvc.VirtualFileResult.ExecuteResultAsync(ActionContext context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultAsync(IActionResult result)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext<TFilter, TFilterAsync>(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeNextResultFilterAsync<TFilter, TFilterAsync>()
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext<TFilter, TFilterAsync>(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

事实证明,解决起来非常简单。只需要返回Content而不是File

但需要大量的实验。

case BarcodeService.Format.Svg:
{
var data = barcodeService.GenerateQRCodeSvg(uri);
return Content(data, "image/svg+xml);
}

这里是一个Asp.Net核心操作返回一个带有动态颜色的复选圈svg的例子。

[Route("/demo/dynamic-svg")]
public IActionResult DynamicSvg()
{
var green = "#008000";
var orange = "#ffc862";
var data = @$"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
<svg width=""510.774"" height=""512"" viewBox=""0 0 135.142 135.467"" xml:space=""preserve"" xmlns=""http://www.w3.org/2000/svg"">
<path style=""fill:{green};stroke-width:.264583"" d=""M129.845 25.892c-1.085 0-2.17.417-2.99 1.25L95.978 58.02 82.034 44.075a4.2 4.2 0 0 0-5.98 0 4.2 4.2 0 0 0 0 5.98l16.934 16.933a4.2 4.2 0 0 0 5.98 0l33.866-33.866a4.2 4.2 0 0 0 0-5.98 4.18 4.18 0 0 0-2.99-1.25z"" transform=""translate(-37.573 20.686)""/>
<path style=""fill:{orange};stroke-width:.264583"" d=""M37.573 40.683h12.779a54.456 54.456 0 0 1 11.536-27.808l-9.049-9.048c-8.44 10.213-13.97 22.912-15.266 36.856zM70.857 3.88C78.69-2.312 88.24-6.44 98.665-7.656V-20.41C84.72-19.113 72.02-13.583 61.808-5.143l9.023 9.023zm40.508 97.816v12.78c13.943-1.297 26.643-6.827 36.856-15.267l-9.022-9.022c-7.832 6.19-17.383 10.318-27.808 11.535zm36.803-20.505 9.023 9.022c8.44-10.186 13.97-22.913 15.266-36.856h-12.78a54.456 54.456 0 0 1-11.535 27.807zm-86.36 18.018c10.187 8.44 22.913 13.97 36.857 15.266v-12.78A54.456 54.456 0 0 1 70.857 90.16Zm-8.969-8.97 9.022-9.022C55.67 73.386 51.543 63.834 50.325 53.41H37.573c1.296 13.918 6.826 26.618 15.266 36.83zm95.382-95.382c-10.213-8.44-22.913-13.97-36.856-15.266v12.78a54.456 54.456 0 0 1 27.808 11.535l9.022-9.022zm-.053 18.018c6.192 7.832 10.32 17.383 11.536 27.808h12.78c-1.297-13.944-6.827-26.643-15.267-36.856l-9.022 9.022z"" transform=""translate(-37.573 20.686)""/>
<path style=""fill:{green};stroke-width:.264583"" d=""M104.982-20.686c-.194 0-.387.006-.58.007v12.7c.193-.002.386-.007.58-.007 30.4 0 55.033 24.632 55.033 55.033 0 30.4-24.633 55.033-55.033 55.033-.194 0-.387-.005-.58-.007v12.7c.193.002.386.007.58.007 37.412 0 67.733-30.32 67.733-67.733 0-37.412-30.321-67.733-67.733-67.733z"" transform=""translate(-37.573 20.686)""/>
</svg>";
return Content(data, "image/svg+xml");
}

最新更新