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:
- Go to nuget.devexpress.com and copy your DevExpress NuGet feed URL.
- 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:
Codedotnet run
To run the Docker container from the command line, build the Docker image:
Windows
Codecd ReportingWebApp
docker build -t reporting-app --secret id=dxnuget,source=secrets.dev.yaml .
docker run -p 8080:80 reporting-app:latest
Linux
Codecd 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
- Startup.cs
- secrets.dev.yaml
The file that contains your NuGet feed URL. - ReportingWebApp.csproj
TheDockerfileFile
property in the project file specifies the name of the docker file to use in the project. Sample docker files for different operating systems are included in the project. You should edit the project file manually to replace the default Debian docker file with docker files for Alpine, Ubuntu or Amazon Linux. For more information on build properties in a project file, review the following help topic: Container Tools build properties. - Dockerfile
The Debian docker file. - Dockerfile.Alpine
The Alpine docker file. - Dockerfile.Ubuntu
The Ubuntu docker file. - Dockerfile.AmazonLinux
The Amazon Linux docker file. - Dockerfile.OpenSuse
The OpenSuse docker file.
Does this example address your development requirements/objectives?
(you will be redirected to DevExpress.com to submit your response)
Example Code
Code# YOUR_NUGET_FEED_URL
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?}");
});
}
}
}
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>
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"]
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"]
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"]
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"]