August 23, 2021

HttpPostedFile vs HttpPostedFileBase

While working with posted files in .Net MVC, you might have stuck with HttpPostedFileBase and HttpPostedFile. These classes have the same properties, but are not related. You can not cast one to the other, because they are completely different objects to .net.

HttpPostedFileBase is an abstract class, used solely for the purpose of being derived from. It is used to mock certain things in sealed class HttpPostedFile. To make things consistent, HttpPostedFileWrapper was created to convert HttpPostedFile to HttpPostedFileBase.

  • HttpPostedFile is a class representing posted files, its definitation looks like this:

    public sealed class HttpPostedFile
    

    This class can't be inherited and can't be mocked for unit testing.

  • HttpPostedFileBase is a unified abstraction, enables the developer to create mockable objects.

    public abstract class HttpPostedFileBase
    
  • HttpPostedFileWrapper is an implementation of HttpPostedFileBase that wraps HttpPostedFile. It looks like this:

    public class HttpPostedFileWrapper : HttpPostedFileBase
    {
    	public HttpPostedFileWrapper(HttpPostedFile httpPostedFile) 
    	{
    		//
    	};
    	//...
    

Create HttpPostedFileBase object from HttpPostedFile:

You can use HttpPostedFileWrapper class, which will accept HttpPostedFile object as a parameter to its constructor.

//suppose httpPostedFile is an object of HttpPostedFile class
HttpPostedFileWrapper httpPostedFileWrapper = new HttpPostedFileWrapper(httpPostedFile);
HttpPostedFileBase httpPostedFileBase = httpPostedFileWrapper; //HttpPostedFileBase is the parent class

Thanks to polymorphism, you can pass an instance of derived class (HttpPostedFileWrapper), to method accepting base class(HttpPostedFileBase)

Create HttpPostedFile object from HttpPostedFileBase:

Creating HttpPostedFile object is not straight similar as it is in above case. You have to make use of System.Reflection to achieve this:

var constructorInfo = typeof(HttpPostedFile).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)[0];
var httpPostedFile = (HttpPostedFile)constructorInfo
		  .Invoke(new object[] { httpPostedFileBase.FileName, httpPostedFileBase.ContentType, httpPostedFileBase.InputStream });

August 19, 2021

.NET Core Worker Service - Implementing by BackgroundService

In this post we will see an example how to define Worker Service by inheriting the BackgroundService abstract base class.

I am using Visual Studio 2019 Community Edition and .Net Core framework 3.1. Lets start creating new project.

Create a new project.

Select the template Worker Service from all the available templates. You can search with relevant keywords from the top search bar.

Next, give project a name, in this example it is WorkerService1.

Next, select the target framework. (.Net Core 3.1 is selected in this example)

Define the service

Once the project is created, create a new class, say ProcessMessageService with this code:

    public class ProcessMessageService : BackgroundService
    {
        public ProcessMessageService()
        {

        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                //do actual work here...
                //we are writing log to text file every 5 seconds

                string folderPath = @"C:\Test\WorkerService\";
                string fileName = "ProcessMessageService-" + DateTime.Now.ToString("yyyyMMdd-HH") + ".txt";
                string filePath = System.IO.Path.Combine(folderPath, fileName);
                string content = DateTime.Now.ToString("yyyyMMdd-HH:mm:ss") + " - ProcessMessageService is running" + Environment.NewLine;

                System.IO.File.AppendAllText(filePath, content);

                await Task.Delay(5000, stoppingToken);
            }
        }
    }
	

ProcessMessageService class is inherited from BackgroundService abstract base class, which in turn implements the IHostedService interface, so ProcessMessageService class can override two functions:

  • public Task StartAsync(CancellationToken cancellationToken): will be called when the service is started.
  • public async Task StopAsync(CancellationToken cancellationToken): will be called when the service is shutdown/stopped.

But in this example, we have only override the BackgroundService's abstract method ExecuteAsync():

    protected abstract Task ExecuteAsync(CancellationToken stoppingToken);
	
Whithin this method, we have defined the actual work for the service, in this exmaple it is writing to text log file by every 5 seconds. We have implemented the indefinite while loop which will keep checking for stoppingToken.IsCancellationRequested bool property as a termination condition.
	while (!stoppingToken.IsCancellationRequested)
	
One each iteration we are suspending the execution by 5 seconds using Task.Delay() method.
	await Task.Delay(5000, stoppingToken);
	

Install required dependencies

Make sure you have installed the following Nuget Packages for .Net Core 3.1, which are required to succefully build and publish the service and enable it to host in windows services.

  • Install-Package Microsoft.CodeAnalysis.Common -Version 3.11.0
  • Install-Package Microsoft.Extensions.Hosting -Version 3.1.17
  • Install-Package Microsoft.Extensions.Hosting.WindowsServices -Version 3.1.17

If you are using some later version of .Net Core, you may need to change the version of these Nuget Packages.

Register the IHostedService

In Program.cs file, you will find the function CreateHostBuilder() as:

public static IHostBuilder CreateHostBuilder(string[] args) =>
	Host.CreateDefaultBuilder(args)
	.ConfigureServices((hostContext, services) =>
	{
		services.AddHostedService<ProcessMessageService>();
	});
		

Make sure that in builder's ConfigureServices() method, you are adding your service through services.AddHostedService() function call.

Another important point is to call UseWindowsService() method from builder's object, otherwise you may get errors when you host this windows service and try to start it.

After making this change, the function will be like this:

public static IHostBuilder CreateHostBuilder(string[] args) =>
	Host.CreateDefaultBuilder(args)
	.UseWindowsService()
	.ConfigureServices((hostContext, services) =>
	{
		services.AddHostedService<ProcessMessageService>();
	});
		

References:

Related Post(s):

SC – Service Console commands

The Service Controller utility SC is a powerful command-line utility for managing Windows services. It modifies the value of a service's entries in the registry and in the Service Control Manager database. As a command-line utility, it is being avialable for scripts and enables the user to Create, Start or Stop or Delete windows services.

If you run the command sc without any arguments, it will list down all the available commands/options with short a description of each command.

If you append a command name (without options), it will display help about that particular command.

You can use the following commands to Create, Start, Stop and Delete a service.

Create a Service

create: Creates a service. (adds service to the registry).

sc.exe create <servicename>  binpath= <binpath> 

Where <servicename> is the name of service and <binpath> is the path to the service's exe file.

For example, this command will create a service from MyWorkerService.exe.

sc.exe create MyWorkerService  binpath= "C:\Apps\MyWorkerService.exe" 

This will create a new service, but it will not be started automatically, if you want to auto start the service you can use the option start= auto

Above command will become:
sc.exe create MyWorkerService  binpath="C:\Apps\MyWorkerService.exe" start= auto

Auto option enables the service to automatically start each time the computer is restarted and runs even if no one logs on to the computer.

Start a Service

start: it will send a START request to the service.

sc.exe start "MyWorkerService"

Stop a Service

stop: it will send a STOP request to the service.

sc.exe start "MyWorkerService"

Delete a Service

delete: Deletes a service from SC Manager and (from the registry).

sc.exe delete "MyWorkerService"
A Note for .Net Core Worker Service

If you are deploying .Net Core Worker Service's exe, make sure to add these NuGet Packages before publishing.

  • Install-Package Microsoft.Extensions.Hosting -Version 3.1.17
  • Install-Package Microsoft.Extensions.Hosting.WindowsServices -Version 3.1.17

Version mentioned in above commands is compatible with .Net Core 3.1. If you are using some later version of .Net Core, you may need to change the version of these Nuget Packages.

References:

Related Post(s):

August 17, 2021

Publish .NET Core Worker Service

In the last post we have created a new Worker Service Project, now we will publish that as a single exe file.

To host the .NET Worker Service app as a Windows Service, it will need to be published as a single file executable.

Before moving forward to publish to project, make sure you have installed the following Nuget Packages for .Net Core 3.1.

  • Install-Package Microsoft.CodeAnalysis.Common -Version 3.11.0
  • Install-Package Microsoft.Extensions.Hosting -Version 3.1.17
  • Install-Package Microsoft.Extensions.Hosting.WindowsServices -Version 3.1.17

If you are using some later version of .Net Core, you may need to change the version of these Nuget Packages.

To publish our .Net Worker Service project as a single file exe, we have to make some changes in WorkerService1.csproj file.

Right click on the project and select Edit Project File.

Add the following childe nodes inside PropertyGroup node.

  • <OutputType>exe</OutputType>
  • <PublishSingleFile>true</PublishSingleFile>
  • <RuntimeIdentifier>win-x64</RuntimeIdentifier>
  • <PlatformTarget>x64</PlatformTarget>
  • <IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>

Here is the description of each line (Credits Microsoft Docs ).

  • <OutputType>exe</OutputType>: Creates a console application.
  • <PublishSingleFile>true</PublishSingleFile>: Enables single-file publishing.
  • <RuntimeIdentifier>win-x64</RuntimeIdentifier>: Specifies the RID of win-x64.
  • <PlatformTarget>x64</PlatformTarget>: Specify the target platform CPU of 64-bit.
  • <IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>: Embeds all required .dll files into the resulting .exe file.

To publish the project from Visual Studio wizard, you need to create a publish profile.

Right click on the project and select Publish...

Select Add a publish profile, Publish dialog will apear, select Folder from the Target tab, and click Next.

In Folder location textbox set the target path where you want to publish the output content.

Click Next, and it will display the Publish profile view.

Select Show all settings link. Profile settings dialog will appear.

Change the Deployment mode to Self-Contained.

Under File publish options, select all the CheckBoxes as true:

  • Produce single file
  • Enable ReadyToRun compilation
  • Trim unused assemblies (in preview)

Click Save button on the Profile settings dialog.

Finally, click the Publish button. It will rebuild the project, and the resulting exe file will be published to the /publish output directory.

Alternatively, you could use the .NET CLI to publish the app, run this command from project root directory:

dotnet publish --output "C:\MyPath\PublishedOutput"

After the publish operation succeeded, it will generate files similar to the following:

We have published Worker Service project in a single exe file. Next step is to host this exe as a Windows Service, which will be covered in the next post.

References:

Related Post(s):

August 16, 2021

.NET Core Worker Service - Implementing by IHostedService

In ASP.NET Core, background tasks can be implemented as hosted services.

ASP.NET Core 3 offers a new feature to implement Windows Service, i.e. Worker Service.

Worker Service is an ASP.NET Core project template that allows you to create long-running background services. The interesting point is that dependency injection is available natively with Worker Service project template.

You can implement Worker Service class by two ways:

  • Implement the IHostedService interface
  • Derive from BackgroundService abstract base class

In this post we will see an example how to define Worker Service by implementing the IHostedService interface.

I am using Visual Studio 2019 Community Edition and .Net Core framework 3.1. Lets start creating new project.

Create a new project.

Select the template Worker Service from all the available templates. You can search with relevant keywords from the top search bar.

Next, give project a name, in this example it is WorkerService1.

Next, select the target framework. (.Net Core 3.1 is selected in this example)

Define the service

Once the project is created, create a new class, say ProcessMessageService with this code:

public class ProcessMessageService : IHostedService
    {
        public Task StartAsync(CancellationToken cancellationToken)
        {
            DoWork(cancellationToken).GetAwaiter().GetResult();
            
            return Task.CompletedTask;
        }

        private async Task DoWork(CancellationToken cancellationToken)
        {
	//check if service is not canceled
            while (!cancellationToken.IsCancellationRequested)
            {
		//do actual work here...
		//we are writing log to text file every 5 seconds
				
		string folderPath = @"C:\Test\WorkerService\";
                string fileName = "ProcessMessageService-" + DateTime.Now.ToString("yyyyMMdd-HH") + ".txt";
                string filePath = System.IO.Path.Combine(folderPath, fileName);
                string content = DateTime.Now.ToString("yyyyMMdd-HH:mm:ss") + " - ProcessMessageService is running" + Environment.NewLine;

                System.IO.File.AppendAllText(filePath, content);

                await Task.Delay(5000, cancellationToken);
            }
        }

        public async Task StopAsync(CancellationToken cancellationToken)
        {
            await Task.Delay(-1, cancellationToken);

            cancellationToken.ThrowIfCancellationRequested();
        }
    }
	

ProcessMessageService class has implemented the interface IHostedService, so it have to define two functions:

  • public Task StartAsync(CancellationToken cancellationToken): will be called when the service is started.
  • public async Task StopAsync(CancellationToken cancellationToken): will be called when the service is shutdown/stopped.

Inside StartAsync() method, we have called our custom method DoWork() which will actually do the job we want this service to do. In this exmaple it is writing to text log file by every 5 seconds.

Install required dependencies

Make sure you have installed the following Nuget Packages for .Net Core 3.1.

  • Install-Package Microsoft.CodeAnalysis.Common -Version 3.11.0
  • Install-Package Microsoft.Extensions.Hosting -Version 3.1.17
  • Install-Package Microsoft.Extensions.Hosting.WindowsServices -Version 3.1.17

If you are using some later version of .Net Core, you may need to change the version of these Nuget Packages.

Register the IHostedService

In Program.cs file, you will find the function CreateHostBuilder() as:
public static IHostBuilder CreateHostBuilder(string[] args) =>
	Host.CreateDefaultBuilder(args)
	.ConfigureServices((hostContext, services) =>
	{
		services.AddHostedService<ProcessMessageService>();
	});
		

Make sure that in builder's ConfigureServices() method, you are adding your service through services.AddHostedService() function call.

Another important point is to call UseWindowsService() method from builder's object, otherwise you may get errors when you host this windows service and try to start it.

After making this change, the function will be like this:

public static IHostBuilder CreateHostBuilder(string[] args) =>
	Host.CreateDefaultBuilder(args)
	.UseWindowsService()
	.ConfigureServices((hostContext, services) =>
	{
		services.AddHostedService<ProcessMessageService>();
	});
		

The coding part is done, next step is to publish the Worker Service to an exe file, which will be covered in next post.

References:

Related Post(s):