by Joche Ojeda | Dec 30, 2022 | C#
In this article, we will be discussing why it is sometimes useful to wrap your synchronous implementation in an asynchronous implementation.
Introduction
Async programming is an important paradigm in modern software development, allowing you to perform long-running tasks without blocking the calling thread. Async programming is particularly useful in scenarios where the operation may take a long time to complete, or when the operation is interacting with a slow resource, such as a network or a database.
One common scenario where you may need to wrap your synchronous implementation in an asynchronous implementation is when you are working with an API or a library that does not provide async versions of its methods. In these cases, you can use the Task.Run
method to wrap the synchronous methods in a task, allowing you to use the await
keyword to asynchronously wait for the operation to complete.
Example: Wrapping a Synchronous Data Processor
To illustrate this concept, let’s consider the following synchronous IDataProcessor
interface:
public interface IDataProcessor
{
void ProcessData(IEnumerable<IData> data);
}
This interface has a single method, ProcessData
, which takes an IEnumerable
of IData
objects as input and processes the data.
Now let’s say that you want to use this IDataProcessor
interface in an async context, but the interface does not provide an async version of the ProcessData
method. To use this interface asynchronously, you can create an async wrapper class that wraps the synchronous implementation in an async implementation.
Here is an example of how you can wrap the synchronous IDataProcessor
implementation in an asynchronous implementation:
public class AsyncDataProcessor : IDataProcessor
{
private readonly IDataProcessor _dataProcessor;
public AsyncDataProcessor(IDataProcessor dataProcessor)
{
_dataProcessor = dataProcessor;
}
public Task ProcessDataAsync(IEnumerable<IData> data)
{
return Task.Run(() => _dataProcessor.ProcessData(data));
}
}
This implementation has a single method, ProcessDataAsync
, which takes an IEnumerable
of IData
objects as input and asynchronously processes the data. The implementation uses the Task.Run
method to wrap the synchronous ProcessData
method in a task, allowing it to be called asynchronously using the await
keyword.
To use this implementation, you can simply create an instance of AsyncDataProcessor
and call the ProcessDataAsync
method, passing in the list of data as an argument. For example:
var dataProcessor = new AsyncDataProcessor(new DataProcessor());
await dataProcessor.ProcessDataAsync(data);
This code creates an instance of the AsyncDataProcessor
class and calls the ProcessDataAsync
method, passing in the data
object as an argument. The await
keyword is used to asynchronously wait for the data processing to complete.
Conclusion
In this article, we discussed why it is sometimes useful to wrap your synchronous implementation in an asynchronous implementation. We used the Task.Run
method to wrap a synchronous IDataProcessor
implementation in an async implementation, allowing us to use the await
keyword
by Joche Ojeda | Dec 30, 2022 | C#
In this article, we will be discussing how to define an async interface based on a synchronous interface example.
Introduction
Async interfaces are useful when you need to perform asynchronous operations within your application. Async interfaces allow you to define methods that return a Task
object instead of a value, allowing you to use the await
keyword to asynchronously wait for the operation to complete.
One important aspect of async programming is the ability to cancel an async operation. This is particularly useful in scenarios where the async operation may take a long time to complete, or when the operation is no longer needed. To support cancellation in async operations, you can use a cancellation token.
Step 1: Define the Synchronous Interface
The first step in defining an async interface is to define the synchronous version of the interface. This will serve as the basis for the async interface.
Here is an example of a synchronous interface:
public interface IDataProcessor
{
void ProcessData(IEnumerable<IData> data);
}
This interface has a single method, ProcessData
, which takes an IEnumerable
of IData
objects as input and processes the data.
Step 2: Define the Async Interface
Now that we have defined the synchronous interface, we can define the async version of the interface. To do this, we simply need to modify the ProcessData
method to return a Task
object instead of void, and add the async
keyword to the method.
Here is the async version of the IDataProcessorAsync
interface:
public interface IDataProcessorAsync
{
Task ProcessDataAsync(IEnumerable<IData> data, CancellationToken cancellationToken);
}
In this version of the interface, we have added a cancellationToken
parameter to the ProcessDataAsync
method. This parameter is of type CancellationToken
, which is a struct that represents a cancellation request.
Step 3: Implement the Async Interface
Now that we have defined the async version of the interface, we can implement it in a class. To implement the async interface, we simply need to define a method that matches the signature of the ProcessDataAsync
method and uses the await
keyword to asynchronously perform the data processing.
Here is an example of an async implementation of the IDataProcessorAsync
interface:
public class DataProcessor : IDataProcessorAsync
{
public async Task ProcessDataAsync(IEnumerable<IData> data, CancellationToken cancellationToken)
{
// Process the data asynchronously
await Task.Delay(1000, cancellationToken);
}
}
This implementation has a single method, ProcessDataAsync
, which takes an IEnumerable
of IData
objects and a cancellationToken
as input and asynchronously processes the data. In this example, the data processing is simulated using the Task.Delay
method, which causes the task to wait for a specified amount of time before completing. The cancellationToken
is passed to the Task.Delay
method as an argument, allowing the task to be cancelled if a cancellation request is made.
Step 4: Use the Async Interface
Now that we have defined and implemented the async interface, we can use it in our application. To use the async interface, we simply need to create an instance of the implementing class and call the async method using the await
keyword.
Here is an example of how to use the async IDataProcessor
interface:
var cts = new CancellationTokenSource();
var dataProcessor = new DataProcessor();
await dataProcessor.ProcessDataAsync(data, cts.Token);
This code creates a CancellationTokenSource
object, which is used to create and manage a cancellation token. The cts.Token
property is then passed to the ProcessDataAsync
method as a cancellation token. The await
keyword is used to asynchronously wait for the data processing to complete.
To cancel the async operation, you can call the Cancel
method on the CancellationTokenSource
object. This will trigger a cancellation request, which will cause the ProcessDataAsync
method to throw a TaskCanceledException
when the await
keyword is encountered.
cts.Cancel();
Conclusion
In this article, we discussed how to define an async interface based on a synchronous interface example, including the use of a cancellation token. We defined the synchronous version of the interface, modified it to include a cancellation token and return a Task
object, implemented the async interface in a class, and demonstrated how to use your new async interface implementation.
by Joche Ojeda | Nov 24, 2022 | Uncategorized
Modern AspNetCore applications use the built-in web server kestrel,this server is usually bound to the localhost address using the ports 5000 and 5001 for http and https.
But what if you want to run 2 applications in the same server? then you have a problem because if you use the default ports one of the applications will not start correctly.
This can easily be solved by changing the default ports in your WebHostBuilder as shown below
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => {
webBuilder.UseUrls("http://0.0.0.0:8016");
webBuilder.UseStartup<Startup>();
});
The problem with the example above is that the URLs are hardcoded, so here is a better solution
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => {
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("hosting.json", optional: true)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddCommandLine(args)
.AddEnvironmentVariables()
.Build();
webBuilder.UseUrls(config["server.urls"]);
webBuilder.UseStartup<Startup>();
});
the example above uses a configuration builder to merge the appsettings.json and the hosting.json in a single configuration object, then with use the value of the property “server.urls” as base URL/port for our application
Here is the content of the hosting.json file
{
"server.urls": "http://0.0.0.0:8016"
}
by Joche Ojeda | Nov 24, 2022 | Uncategorized
Sometime we want to reuse our Blazor components in another apps, the best way to do this is to create a razor library, this process of create a razor library is not different from create a normal class library to share code. There is only one exception, razor components might need to reference JavaScript or CSS files. This problem can be easily solve in 2 steps as shown below.
1) Create a class that inherits from TagHelperComponent,,this class should include the tags that you want to include in the html header section of your app
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Razor.TagHelpers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyBlazorApp
{
[HtmlTargetElement("head")]
public class MyTagHelper: TagHelperComponent
{
private string Tags=
@"
<!-- ZXingBlazor -->
<script src=""_content/ZXingBlazor/lib/barcodereader/zxing.js""></script>
<script src = ""_content/ZXingBlazor/lib/barcodereader/barcode.js"" ></ script >
< !--ZXingBlazor-- >
< !--Signature Pad -->
<script src = ""_content/Mobsites.Blazor.SignaturePad/bundle.js"" ></ script >
< link href=""_content/Mobsites.Blazor.SignaturePad/bundle.css"" rel=""stylesheet"" />
< link href=""_content/Ultra.PropertyEditors.Module.Blazor/js/signaturepropertyeditor.js""/>
<!-- Signature Pad -->
<!-- HTML Editor -->
<link href = ""//cdn.quilljs.com/1.3.6/quill.snow.css"" rel=""stylesheet"">
<link href = ""//cdn.quilljs.com/1.3.6/quill.bubble.css"" rel=""stylesheet"">
<script src = ""https://cdn.quilljs.com/1.3.6/quill.js"" ></ script >
<script src=""_content/Blazored.TextEditor/quill-blot-formatter.min.js""></script>
<script src = ""_content/Blazored.TextEditor/Blazored-BlazorQuill.js"" ></ script >
< !--HTML Editor -->
";
public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
if (string.Equals(context.TagName, "head", StringComparison.OrdinalIgnoreCase))
{
output.PostContent.AppendHtml(Tags).AppendLine();
}
return Task.CompletedTask;
}
}
}
*Note: to reference JavaScript or CSS from any razor library you can use the following syntax,please notice the doble quotes.
<script src=""_content/MyAssemblyName/PathToMyJavaScript/MyJavaScriptFile.js""></script>
2) Create an extension method in the “Microsoft.Extensions.DependencyInjection” namespace so you can easily add your tag helper to the service collection
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.Extensions.DependencyInjection
{
public static class StartupExtensions
{
public static IServiceCollection AddMyHtmlTags(this IServiceCollection services)
{
services.AddTransient<ITagHelperComponent, MyTagHelper>();
return services;
}
}
}
Here is an example on how to use your new extension in your startup class
public void ConfigureServices(IServiceCollection services
{
services.AddMyHtmlTags();
}
by Joche Ojeda | Nov 18, 2022 | XAF
The LogLevel section in the appsettings.json file does not affect the .NET Framework tracing mechanism, which is used by XPO to log the queries, still we have a few work arounds for a Netcore app
- We can implement our own logger as shown here https://docs.devexpress.com/XPO/403928/best-practices/how-to-log-sql-queries#xpo-logger-net
- We can set the value of the logging switch by reflection using the following snippet
private static void EnableXpoDebugLog()
{
FieldInfo xpoSwitchF = typeof(ConnectionProviderSql).GetField("xpoSwitch", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
TraceSwitch xpoSwitch = (TraceSwitch)xpoSwitchF.GetValue(null);
xpoSwitch.Level = TraceLevel.Info;
}
I actually use the second work around in my own projects.
If you want to learn more about the logging mechanism of XPO you can take a look to the following articles
https://supportcenter.devexpress.com/ticket/details/t1033081/how-to-log-the-sql-queries-made-by-xpo-in-net-5-applications
https://supportcenter.devexpress.com/ticket/details/t913939/enable-logging-in-xaf-blazor