Hello,
Please could you give us an example of how to write binary data to the http response stream from an action inside an XAF Blazor application?
Best regards
Hello,
Please could you give us an example of how to write binary data to the http response stream from an action inside an XAF Blazor application?
Best regards
Hello Axel,
Please refer to this help topic for a solution: How to: Download a File in XAF Blazor Applications.
We do not have public and documented XAF's API for this particular task.
I recommend that you use standard solutions from public community resources for ASP.NET Core Blazor Server here. For instance, https://stackoverflow.com/questions/58527572/is-there-a-way-to-get-a-file-stream-to-download-to-the-browser-in-blazor or https://github.com/arivera12/BlazorDownloadFile. It is also possible that you will be able to locate more solutions in Microsoft documentation, Google or https://stackoverflow.com/search?q=blazor+download+file. As a rule of thumb, I recommend that you implement this task in a non-XAF app first. XAF integration will be much easier as a result.
If you can do this task from a non-XAF app code, you can do this from XAF Controllers or other places within XAF app code. For instance, in the StackOverFlow thread all that it does is just navigate to an endpoint using the standard NavigationManager service:
C#using DevExpress.ExpressApp;
using Microsoft.AspNetCore.Components;
using DevExpress.ExpressApp.Blazor;
using Microsoft.Extensions.DependencyInjection;
using DevExpress.ExpressApp.Actions;
namespace SolutionName.Module.Blazor.Controllers {
public class OpenUrlController : WindowController {
public OpenUrlController() {
new SimpleAction(this, "OpenUrl", "View", (s, e) => {
var navigationManager = ((BlazorApplication)Application).ServiceProvider.GetRequiredService<NavigationManager>();
navigationManager.NavigateTo("yourPage", forceLoad: true);
});
}
}
}
You can also call JavaScript functions from .NET methods in ASP.NET Core Blazor:
C#var JSRuntime = ((BlazorApplication)Application).ServiceProvider.GetRequiredService<IJSRuntime>();
JSRuntime.InvokeAsync<object>("open", System.Threading.CancellationToken.None, "yourPage", "_blank");
This example shows how to implement a middleware that loads a file from a specified persistent object and sends it to the client. An Action sends a request to this middleware and passes an object's ID to request parameters.
NOTE: XAF already has an API endpoint that can return data from the File Attachment module's IFileData objects. You can send requests to it using the following URL pattern :
https://demos.devexpress.com/XAF/BlazorDemo/IFileUrlService/?objectType=MainDemo.Module.BusinessObjects.Resume&objectKey=1dc9dfd3-7389-4e17-930c-c4018deb4acc&propertyName=File. Use a custom middleware when you need to process file attachments before downloading them or when you need to create a file from another source.
C#using DevExpress.Data.Filtering;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Actions;
using DevExpress.ExpressApp.Blazor;
using dxTestSolution.Module.BusinessObjects;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Linq;
namespace dxTestSolution.Module.Controllers {
public class CustomBlazorController : ViewController {
public CustomBlazorController() {
var myAction1 = new SimpleAction(this, "MyBlazorAction1", null);
myAction1.Execute += MyAction1_Execute;
}
private void MyAction1_Execute(object sender, SimpleActionExecuteEventArgs e) {
var os = Application.CreateObjectSpace(typeof(Contact));
var cnt = os.FindObject<Contact>(new BinaryOperator("FirstName", "FirstName1"));
var url = "IMyCustomService/?myKey=" + cnt.Oid;
var navigationManager = ((BlazorApplication)Application).ServiceProvider.GetRequiredService<NavigationManager>();
navigationManager.NavigateTo(url, forceLoad: true);
}
}
}
C#using DevExpress.ExpressApp.Blazor.Services;
using dxTestSolution.Module.BusinessObjects;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
namespace dxT1097529.Blazor.Server {
public class MyCustomMiddleware {
private readonly RequestDelegate next;
public MyCustomMiddleware(RequestDelegate next) {
this.next = next;
}
public async Task InvokeAsync(HttpContext httpContext, IXafApplicationProvider applicationProvider) {
if(httpContext.Request.Path.Value!.TrimStart('/').StartsWith("IMyCustomService", StringComparison.Ordinal)) {
var app = applicationProvider.GetApplication();
var os = app.CreateObjectSpace(typeof(Contact));
var keySt = httpContext.Request.Query["myKey"][0];
var key = os.GetObjectKey(typeof(Contact), keySt);
var contact = os.GetObjectByKey<Contact>(key);
var fileData = contact.File;
MemoryStream stream = new MemoryStream();
fileData.SaveToStream(stream);
stream.Position = 0;
httpContext.Response.ContentType = "application/pdf";
httpContext.Response.Headers.Add("Content-Disposition", "attachment; filename=" + fileData.FileName);
await StreamCopyOperation.CopyToAsync(stream, httpContext.Response.Body, new long?(), 65536, httpContext.Response.HttpContext.RequestAborted);
} else {
await next(httpContext);
}
}
}
}
C#namespace dxT1097529.Blazor.Server {
public class Startup {
//...
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
//...
app.UseXaf();
app.UseMiddleware<MyCustomMiddleware>();
//...
}
}
}
I attached a simple example that illustrates this solution.
Feel free to contact us if you have any XAF-specific questions or issues - we will be more than happy to help you.
Hello Stanley,
I want to do the exact same thing, but the only difference is – I want to implement this in ListView
. Now, in the ListView
I would be having multiple objects, and for each of those selected objects I want to download a text file.
So the problem with NavigationManager
is that after sending a request for first object it doesn't wait for its response, and sends another request for next object immediately. This behavior results into missing out actions being performed on every selected objects.
So, is there any alternative for sending a request to Web API Controller from ViewController
in any proper way?
Thanks,
Rushit.
Hello Rushit,
Instead of using the Navigation Manager, you can get an IJSRuntime instance from services and use its methods to invoke a JavaScript function that opens the specified URL in a new tab/window. This idea is demonstrated in the following thread: Blazor Open a page in a new Browser tab using navigation manager?. Here is an example:
C#private async void Action_Execute(object sender, SimpleActionExecuteEventArgs e) {
var JSRuntime = ((BlazorApplication)Application).ServiceProvider.GetRequiredService<IJSRuntime>();
await JSRuntime.InvokeVoidAsync("open", "/api/Test", "_blank");
}
Let us know if you have further questions.
Thanks,
Stanley
Hello Axel,
Please refer to this help topic for a solution: How to: Download a File in XAF Blazor Applications.
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.