Example T1133108
Visible to All Users

Reporting for ASP.NET Core - How to Use the SkiaSharp-Based DevExpress Drawing Engine

This example demonstrates how to use the DevExpress.Drawing package based on the SkiaSharp library instead of the System.Drawing library in an ASP.NET Core application to preview, print, or export DevExpress XtraReports.

The commands required to configure the host operating system environment for the DevExpress Drawing Engine are included in the docker file.

How to Build and Run this Example

Specify the NuGet Feed URL for Docker

To restore NuGet packages while building a Docker image, you should pass the DevExpress NuGet feed URL as a secret as follows:

  1. Go to nuget.devexpress.com and copy your DevExpress NuGet feed URL.
  2. Paste the copied feed URL to the secrets.dev.yaml file located in the project.

Run the Example

Visual Studio

You can run the app on the Windows platform, or the Windows Subsystem for Linux or Docker. If you want to launch the app with docker, select Docker from the Launch drop-down menu in the Visual Studio toolbar.

CLI

Run the application from the dotnet CLI on Windows, Linux, and MacOS with the following command:

Code
dotnet run

To run the Docker container from the command line, build the Docker image:

Windows

Code
cd ReportingWebApp docker build -t reporting-app --secret id=dxnuget,source=secrets.dev.yaml . docker run -p 8080:80 reporting-app:latest

Linux

Code
cd ReportingWebApp DOCKER_BUILDKIT=1 docker build -t reporting-app --secret id=dxnuget,source=secrets.dev.yaml . docker run -p 8080:80 reporting-app:latest

The application page is available at the following URL: http://localhost:8080/.

Review the Docker documentation for more information: BuildKit documentation.

If your secrets.dev.yaml contains the byte order mark (BOM), you can get an error while restoring NuGet packages. To avoid this potential problem, make sure your secrets.dev.yaml encoding does not contain the BOM.

Files to Review

Does this example address your development requirements/objectives?

(you will be redirected to DevExpress.com to submit your response)

Example Code

ReportingWebApp/secrets.dev.yaml
Code
# YOUR_NUGET_FEED_URL
ReportingWebApp/Startup.cs
C#
using System; using System.IO; using System.Reflection; using System.Runtime.InteropServices; using DevExpress.AspNetCore; using DevExpress.AspNetCore.Reporting; using DevExpress.Security.Resources; using DevExpress.Utils; using DevExpress.XtraReports.Web.Extensions; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using ReportingWebApp.Data; using ReportingWebApp.Services; namespace ReportingWebApp { public class Startup { public Startup(IConfiguration configuration, IWebHostEnvironment environment) { Configuration = configuration; AppDomain.CurrentDomain.SetData("DataDirectory", environment.ContentRootPath); } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddDevExpressControls(); services.AddScoped<ReportStorageWebExtension, CustomReportStorageWebExtension>(); DeserializationSettings.RegisterTrustedClass(typeof(ReportingWebApp.Employees.DataSource)); services .AddMvc() .AddNewtonsoftJson(); services.ConfigureReportingServices(configurator => { configurator.ConfigureReportDesigner(designerConfigurator => { designerConfigurator.RegisterDataSourceWizardConnectionStringsProvider<CustomSqlDataSourceWizardConnectionStringsProvider>(); designerConfigurator.RegisterDataSourceWizardJsonConnectionStorage<CustomDataSourceWizardJsonDataConnectionStorage>(true); designerConfigurator.RegisterObjectDataSourceWizardTypeProvider<ObjectDataSourceWizardCustomTypeProvider>(); }); configurator.ConfigureWebDocumentViewer(viewerConfigurator => { viewerConfigurator.UseCachedReportSourceBuilder(); viewerConfigurator.RegisterJsonDataConnectionProviderFactory<CustomJsonDataConnectionProviderFactory>(); viewerConfigurator.RegisterConnectionProviderFactory<CustomSqlDataConnectionProviderFactory>(); }); configurator.UseAsyncEngine(); }); services.AddDbContext<ReportDbContext>(options => options.UseSqlite(Configuration.GetConnectionString("ReportsDataConnectionString"))); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ReportDbContext db) { db.InitializeDatabase(); app.UseDevExpressControls(); var rootPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); var dataDirectoryAllowRule = DirectoryAccessRule.Allow(new DirectoryInfo(Path.Combine(rootPath, "Data")).FullName); AccessSettings.DataResources.TrySetRules(dataDirectoryAllowRule, UrlAccessRule.Allow()); System.Net.ServicePointManager.SecurityProtocol |= System.Net.SecurityProtocolType.Tls12; if(env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); } } }
ReportingWebApp/ReportingWebApp.csproj
Code
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>net8.0</TargetFramework> <DefaultItemExcludes>Reports\**</DefaultItemExcludes> <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS> <DockerfileFile>Dockerfile</DockerfileFile> <UserSecretsId>7bffbdbd-957d-40bc-92c8-236f2904aaee</UserSecretsId> <DockerfileContext>.</DockerfileContext> <DockerfileBuildArguments>--secret id=dxnuget,source=secrets.dev.yaml</DockerfileBuildArguments> </PropertyGroup> <ItemGroup> <Compile Remove="Reports\**" /> <Content Remove="Reports\**" /> <EmbeddedResource Remove="Reports\**" /> <None Remove="Reports\**" /> </ItemGroup> <ItemGroup> <None Remove="Data\nwind.db" /> </ItemGroup> <ItemGroup> <Content Include="Data\nwind.db"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> </ItemGroup> <ItemGroup> <Content Update="Data\nwind.json"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> </ItemGroup> <ItemGroup> <Compile Remove="node_modules\**" /> <Content Remove="node_modules\**" /> <EmbeddedResource Remove="node_modules\**" /> <None Remove="node_modules\**" /> </ItemGroup> <Target Name="DebugEnsureNodeEnv" BeforeTargets="LibraryManagerRestore" Condition="!Exists('node_modules') "> <!-- Ensure Node.js is installed --> <Exec Command="node --version" ContinueOnError="true"> <Output TaskParameter="ExitCode" PropertyName="ErrorCode" /> </Exec> <Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." /> <Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." /> <Exec Command="npm install" /> </Target> <ItemGroup> <Content Remove="nuget.config" /> </ItemGroup> <ItemGroup> <None Include="nuget.config" /> </ItemGroup> <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.11" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.11" /> <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.0" /> <PackageReference Include="System.Data.SQLite" Version="1.0.119" /> <PackageReference Include="DevExpress.AspNetCore.Reporting" Version="24.2.3" /> <PackageReference Include="BuildBundlerMinifier" Version="3.2.449" /> <PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="2.1.175" /> <PackageReference Include="DevExpress.Drawing.Skia" Version="24.2.3" /> </ItemGroup> </Project>
ReportingWebApp/Dockerfile.Alpine
Code
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine AS base #Install dependencies RUN apk update && apk upgrade RUN apk add icu-libs icu-data-full fontconfig #Install fonts RUN apk add ttf-dejavu && \ apk add msttcorefonts-installer && \ apk add ttf-dejavu && \ update-ms-fonts && \ fc-cache -f WORKDIR /app ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false EXPOSE 80 EXPOSE 443 FROM node:18 as build-frontend WORKDIR /modules COPY ["package.json", "./"] RUN npm install FROM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build WORKDIR /src RUN --mount=type=secret,id=dxnuget,required=true dotnet nuget add source $(cat /run/secrets/dxnuget) -n devexpress-nuget COPY ["ReportingWebApp.csproj", "ReportingWebApp/"] RUN dotnet restore "ReportingWebApp/ReportingWebApp.csproj" COPY ["./", "ReportingWebApp/"] WORKDIR "/src/ReportingWebApp" COPY --from=build-frontend ./modules . RUN dotnet build "ReportingWebApp.csproj" -c Release -o /app/build FROM build AS publish RUN dotnet publish "ReportingWebApp.csproj" -c Release -o /app/publish /p:UseAppHost=false FROM base AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "ReportingWebApp.dll"]
ReportingWebApp/Dockerfile.Ubuntu
Code
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. FROM mcr.microsoft.com/dotnet/aspnet:8.0-jammy AS base #Install dependencies RUN apt-get update RUN apt-get install -y libc6 libicu-dev libfontconfig1 WORKDIR /app EXPOSE 80 EXPOSE 443 FROM node:18 as build-frontend WORKDIR /modules COPY ["package.json", "./"] RUN npm install FROM mcr.microsoft.com/dotnet/sdk:8.0-jammy AS build WORKDIR /src RUN --mount=type=secret,id=dxnuget,required=true dotnet nuget add source $(cat /run/secrets/dxnuget) -n devexpress-nuget COPY ["ReportingWebApp.csproj", "ReportingWebApp/"] RUN dotnet restore "ReportingWebApp/ReportingWebApp.csproj" COPY ["./", "ReportingWebApp/"] WORKDIR "/src/ReportingWebApp" COPY --from=build-frontend ./modules . RUN dotnet build "ReportingWebApp.csproj" -c Release -o /app/build FROM build AS publish RUN dotnet publish "ReportingWebApp.csproj" -c Release -o /app/publish /p:UseAppHost=false FROM base AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "ReportingWebApp.dll"]
ReportingWebApp/Dockerfile.AmazonLinux
Code
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. FROM amazonlinux AS base RUN rpm -Uvh https://packages.microsoft.com/config/centos/7/packages-microsoft-prod.rpm RUN yum install -y aspnetcore-runtime-8.0 #Install dependencies RUN yum install -y glibc-devel libicu fontconfig WORKDIR /app ENV ASPNETCORE_URLS=http://+:80 EXPOSE 80 EXPOSE 443 FROM node:18 as build-frontend WORKDIR /modules COPY ["package.json", "./"] RUN npm install FROM amazonlinux AS build RUN rpm -Uvh https://packages.microsoft.com/config/centos/7/packages-microsoft-prod.rpm RUN yum install -y dotnet-sdk-8.0 WORKDIR /src RUN --mount=type=secret,id=dxnuget,required=true dotnet nuget add source $(cat /run/secrets/dxnuget) -n devexpress-nuget COPY ["ReportingWebApp.csproj", "ReportingWebApp/"] RUN dotnet restore "ReportingWebApp/ReportingWebApp.csproj" COPY ["./", "ReportingWebApp/"] WORKDIR "/src/ReportingWebApp" COPY --from=build-frontend ./modules . RUN dotnet build "ReportingWebApp.csproj" -c Release -o /app/build FROM build AS publish RUN dotnet publish "ReportingWebApp.csproj" -c Release -o /app/publish /p:UseAppHost=false FROM base AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "ReportingWebApp.dll"]
ReportingWebApp/Dockerfile.OpenSuse
Code
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. FROM opensuse/leap AS base RUN zypper -n install wget libicu && \ wget https://packages.microsoft.com/keys/microsoft.asc RUN rpm --import microsoft.asc RUN wget https://packages.microsoft.com/config/opensuse/15/prod.repo && \ mv prod.repo /etc/zypp/repos.d/microsoft-prod.repo && \ chown root:root /etc/zypp/repos.d/microsoft-prod.repo RUN zypper -n install aspnetcore-runtime-8.0 #Install dependencies RUN zypper -n install glibc-devel fontconfig #Install fonts RUN zypper -n install fetchmsttfonts WORKDIR /app ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false ENV ASPNETCORE_URLS=http://+:80 EXPOSE 80 EXPOSE 443 FROM node:18 as build-frontend WORKDIR /modules COPY ["package.json", "./"] RUN npm install FROM opensuse/leap AS build RUN zypper -n install wget libicu && \ wget https://packages.microsoft.com/keys/microsoft.asc RUN rpm --import microsoft.asc RUN wget https://packages.microsoft.com/config/opensuse/15/prod.repo && \ mv prod.repo /etc/zypp/repos.d/microsoft-prod.repo && \ chown root:root /etc/zypp/repos.d/microsoft-prod.repo RUN zypper -n install dotnet-sdk-8.0 WORKDIR /src RUN --mount=type=secret,id=dxnuget,required=true dotnet nuget add source $(cat /run/secrets/dxnuget) -n devexpress-nuget COPY ["ReportingWebApp.csproj", "ReportingWebApp/"] RUN dotnet restore "ReportingWebApp/ReportingWebApp.csproj" COPY ["./", "ReportingWebApp/"] WORKDIR "/src/ReportingWebApp" COPY --from=build-frontend ./modules . RUN dotnet build "ReportingWebApp.csproj" -c Release FROM build AS publish RUN dotnet publish "ReportingWebApp.csproj" -c Release -o /app/publish FROM base AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "ReportingWebApp.dll"]

Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.