Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

December 31, 2023

Microsoft.Data.SqlClient.SqlException: The certificate chain was issued by an authority that is not trusted

I faced this error while using the Entity Framework Core with .Net 6.0,

Microsoft.Data.SqlClient.SqlException: 'A connection was successfully established 
with the server, but then an error occurred during the login process. 
(provider: SSL Provider, error: 0 - The certificate chain was issued by an authority
that is not trusted.)'

Breaking change in Microsoft.Data.SqlClient 4.0.0.

I found there is breaking change in Microsoft.Data.SqlClient - 4.0.0 .

Changed Encrypt connection string property to be true by default:
The default value of the Encrypt connection setting has been changed from false to true. 
With the growing use of cloud databases and the need to ensure those connections are secure, 
it's time for this backwards-compatibility-breaking change.

Ensure connections fail when encryption is required:
In scenarios where client encryption libraries were disabled or unavailable, 
it was possible for unencrypted connections to be made when Encrypt was set to true
or the server required encryption.

Solution

The quick-fix is to add Encrypt=False to your connection-strings.

Alongwith Encrypt=False, setting Trusted_Connection=True would also help.

Another workaround if you are using local computer is to set

TrustServerCertificate=True

Please note that, setting TrustServerCertificate=True is not a real fix. The more authentic part of the solution is installing a CA signed certificate.

References:

December 26, 2023

Serialize with System.Text.Json.JsonSerializer

The System.Text.Json namespace provides functionality for serializing to and deserializing from JavaScript Object Notation (JSON). When serializing C# objects to json, by default all public properties are serialized.

Lets say we have this User class object we want to serialize:

 class User
 {
     public int Id { get; set; }
     public string Name { get; set; }
     public string? Email { get; set; }
     public string Password { get; set; }
 }

var obj = new User
 {
     Id = 1,
     Name = "Idrees",
     Email = null,
     Password = "123"
 };

If we serialize this object:

string txtJson = Json.JsonSerializer.Serialize(obj);

We will get the this json:

{"Id":1,"Name":"Idrees","Email":null,"Password":"123"}

If we want to skip the Password property, we can use the attribute [JsonIgnore] on that property.

After this change the User class will look like this:

 class User
 {
     public int Id { get; set; }
     public string Name { get; set; }
     public string Email { get; set; }
     [JsonIgnore]
     public string Password { get; set; }
 }

Serializing now will give you this result:

{"Id":1,"Name":"Idrees","Email":null}

Notice that the Password property is no longer serialized.

You can also specify the condition for exclusion by setting the [JsonIgnore] attribute's Condition property.

In above example, we have set the null value for Email property and it is showing null in serialized json text.

To exclude that property we can specify the condition to ignore when it has null value. After this change the User class will become like this:

 class User
 {
     public int Id { get; set; }
     public string Name { get; set; }
     [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
     public string? Email { get; set; }
     [JsonIgnore]
     public string Password { get; set; }
 }

The serialization will remove the Email property and generate this json.

{"Id":1,"Name":"Idrees"}

References:

Repeat a String in C#

C# do not have built-in function, as of C# 12.0, to repeat a string for x number of times.

Lets say we have a string variable:

	string text = "-"; //the string we need to repeat
	int n = 5; // number-of-times to repeat

Here are some ways you can use to repeat a string value:

Using Enumerable.Repeat and string.Concat:

	string result1 = string.Concat(Enumerable.Repeat(text, n));

Using StringBuilder:

	string result2 = new StringBuilder().Insert(0, text, n).ToString();

Using Enumerable.Range, Select with string.Concat

	var repeatedStrings = Enumerable.Range(0, n).Select(i => text);
	string result3 = string.Concat(repeatedStrings);

Using String() constructor

If the required string is single character, you can also use String constructor.

	string result4 = new String('-', n);

November 28, 2023

C# Caller Argument Expression Attribute

The System.Runtime.CompilerServices.CallerArgumentExpressionAttribute enables you to receive the expression passed as an argument. It captures the expression passed for another parameter as a string.

This would be helpful specially in diagnostic libraries which need to provide more details about the expressions passed to arguments. By providing the expression that triggered the diagnostic, in addition to the parameter name, developers have more details about the condition that triggered the diagnostic.

Lets say we have this method to log the method name.

public static void LogMethodName(string name, 
                 [CallerArgumentExpression("name")] string? message = null)
{
   if (string.IsNullOrEmpty(name))
   {
      //we are printing the 'message' which represents the actual expression 
      //being passed for parameter 'name'
      throw new ArgumentException($"Argument validation: <{message}>", name);
   }

   Console.WriteLine($"Method {name} is called.");
}

Here we are calling above method:

public static void RegisterUser()
{
    LogMethodName(nameof(RegisterUser));
}

In RegisterUser method, we are calling LogMethodName with the value as name of RegisterUser. The expression used for name parameter, is injected by the compiler into the message argument.

In this example, the expression passed for the name parameter is nameof(RegisterUser), so the value of message parameter in LogMethodName is "nameof(RegisterUser)"

References:

C# documentation comments - para and cref

C# documentation comments use XML elements to define the structure of the output documentation. It helps to write the information about code and makes it more readable and understandable.

<para> tag

The <para> tag can be used inside a tag, such as <summary>, <remarks>, or <returns>. It allows you to add structure to the text.

Here the <para> is used to add another line (paragraph) in the summary section.

/// <summary>
/// This property will keep the type of project.
///     <para>
///         The Type of project defined in the document.
///     </para>
/// </summary>
public string ProjectType { get; set; }

It will display this information on mouse hover like this:

cref attribute

The cref attribute in an XML documentation tag means "code reference." It specifies that the inner text of the tag is a code element, such as a type, method, or property.

Here the cref attribute is referencing another class which contains constant string values.

/// <summary>
///     <para>
///         Use <see cref="MyNamespace.ProjectStatus"/> class.
///     </para>
/// </summary>
public string Status { get; set; }

On mouse hover it will display like this:

Note that the ProjectStatus will appear as link, and will take you to the definition of class when clicked.

References:

September 30, 2023

Enable Tag Helper using @tagHelperPrefix

The @tagHelperPrefix directive allows you to specify a tag prefix string to enable Tag Helper support and to make Tag Helper usage explicit.

For example, you could add the following markup to the Views/_ViewImports.cshtml file:

@tagHelperPrefix cst:

This allows you to enable Tag Helper support by using this prefix (cst). Only those elements using the prefix cst, support the Tag Helpers (Tag Helper-enabled elements have a distinctive font/color).

In the code image below, the <label> element have the Tag Helper prefix (cst), so the Tag Helper is enabled for this element. While the <input> element doesn't have Tag Helper prefix (cst), so Tag Helper is not enabled for this element, this is just a regular HTML element.

The same hierarchy rules that apply to @addTagHelper also apply to @tagHelperPrefix.

References:

Related Post(s):

Tag Helper scope with _ViewImports file

  • The _ViewImports.cshtml can be added to any view folder, and the view engine applies the directives from both that file and the Views/_ViewImports.cshtml file.
  • The _ViewImports.cshtml file is additive, If you add an empty Views/Home/_ViewImports.cshtml file for the Home views, there would be no change because it will import all tag helpers from Views/_ViewImports.cshtml file.
  • If you add new tag helpers in Views/Home/_ViewImports.cshtml file for the Home views, it will import all tag helpers from Views/_ViewImports.cshtml file, also it will import all tag helpers from Views/Home/_ViewImports.cshtml file.
  • Any new @addTagHelper directives you add to the Views/Home/_ViewImports.cshtml file (that are not in the default Views/_ViewImports.cshtml file) would expose those Tag Helpers to views only in the Home folder.

References:

Related Post(s):

August 28, 2023

Remove Tag Helpers with @removeTagHelper

Remove Tag Helpers with @removeTagHelper

The @removeTagHelper removes a Tag Helper that was previously added by @addTagHelper.

It has the same two parameters as @addTagHelper:

@removeTagHelper *, MyApplicationTagHelpers

For example, when you want to restrict a specific Tag Helper on a particular view, you can apply the @removeTagHelper to remove the specified Tag Helper.

Using @removeTagHelper in a child folder's _ViewImports.cshtml file (e.g. Views/Folder/_ViewImports.cshtml), it removes the specified Tag Helper from all of the views in that Folder.

Opting out of individual Tags

Instead of removing the Tag Helper from a View, you can also disable a Tag Helper at the element level with the Tag Helper opt-out character ("!").

For example, we can disable the Email validation in the <span> with the Tag Helper opt-out character:

<!span asp-validation-for="Email" class="text-danger"></!span>

In this case, the Tag Helper will be disabled on a single element (<span> in this case), rather than all elements in a View.

The Tag Helper opt-out character must be applied to the both opening and closing tags.

References:

Related Post(s):

Custom Tag Helpers in ASP.NET Core

Tag Helper allows you to add or modify HTML elements from server-side code. In Razor markup, the Tag Helper looks like standard HTML elements. It provides more productive syntax than manually writing the C# Razor markup.

Tag Helpers enable server-side code to participate in creating and rendering HTML elements in Razor files.

(Microsoft Docs - Tag Helpers in ASP.NET Core)

To create a custom Tag Helper, you need to inherit from built-in TagHelper class. For example we have this Tag Helper,

public class StringTagHelper : TagHelper
{
   public override void Process(TagHelperContext context, TagHelperOutput output)
   {
      output.TagName = "span";
      output.TagMode = TagMode.StartTagAndEndTag;

      output.Attributes.Add("data-entity", "customer");

      base.Process(context, output);
   }
}

This Tag Helper will output the span element and add a custom attribute data-entity with value customer.

In the Razor markup, we can use this Tag Helper as:

<string field="CustomerID"></string>

Ofcourse we can add any extra/custom attributes to html tags, these will not interrupt with Tag Helpers.

The browser will render the final output as:

<span field="CustomerID" data-entity="customer"></span>

To use the Tag Helpers in the views, you need to set its scope, usually we define the scope in Views/_ViewImports.cshtml file.

Tag Helpers scope is controlled by a combination of @addTagHelper, @removeTagHelper, and the "!" opt-out character.

To make the required TagHelper avialable for one or more views we use @addTagHelper.

If you create a new ASP.NET Core web app named MyApplicationTagHelpers, the following Views/_ViewImports.cshtml file will be added to your project:

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, MyApplicationTagHelpers

Some points for above code:

  • The code above uses the wildcard syntax ("*") to specify that all Tag Helpers in the specified assembly (Microsoft.AspNetCore.Mvc.TagHelpers) will be available to every view file in the Views directory or subdirectory.
  • The first parameter after @addTagHelper specifies the Tag Helpers to load ("*" is used to load all Tag Helpers)
  • The second parameter "Microsoft.AspNetCore.Mvc.TagHelpers" specifies the source assembly from which we want to load the Tag Helpers. It can be current project's assemly or any reference to external library.

References:

Related Post(s):

January 24, 2023

C# Yield Return & Break Statements

The yield keyword makes the method (in which it appears) as an iterator block. An iterator block, or method, will return an IEnumerable as the result. Within this iterator block or method, we will use the yield keyword to return the values for the IEnumerable.

Note that IEnumerable is lazily evaluted. If you call a method with an iterator block (with yield keyword), it will not run any code until we actually access the IEnumerable result values.

Lets see an exmaple.

Usually you may find code similiar to this where we are creating a temp list to hold the items, and at the end return the list from a method:

public IEnumerable<int> MyList()
{
	List<int> list = new List<int>();
	list.Add(1);
	list.Add(2);
	list.Add(3);
	list.Add(4);
	list.Add(5);

	return list;
}

You can simplify the method using the yield return statement, it allows us to remove the intermediate/temporary list required to hold the values.

public IEnumerable<int> MyList()
{
	yield return 1;
	yield return 2;
	yield return 3;
	yield return 4;
	yield return 5;
}

This method will return the same list of intergers but it does not need a temporary list to hold values.

You can use the yield break statement to explicitly stop the current iteration and cancel the iterator block. In this case it will return all these values which are produced with yield return statement. Once it reaches the yield break statement, it will stop producing any further value and exit the iterator block.

Lets see this example:

public static IEnumerable<int> MyList()
{
	yield return 1;
	yield return 2;
	yield break;
	yield return 3;
	yield return 4;
	yield return 5;
}

This method will only produce two values 1 and 2. Once it reaches the yield break statement, it will exit from the iterator block.

Typically you would do this when a certain condition is met, you only want to return a specific set of values from the iterator block.

Let see this example:

IEnumerable TakeWhilePositive(IEnumerable<int> numbers)
{
    foreach (int n in numbers)
    {
        if (n > 0)
        {
            yield return n;
        }
        else
        {
            yield break;
        }
    }
}

If you call this method like:

foreach (var item in TakeWhilePositive(new[] { 1, 2, 3, -1, 4, 5}))
{
	Console.WriteLine(item);
}

It will print the values from given array as:

1
2
3

Once it found a negative value, the iteration loop will be stopped and control is returned to the caller method.

References:

September 19, 2022

How to add a custom HTTP header to WCF method call?

I have an environment with SOA architecture spans a number of WCF services. Some of these services need to identity its clients. Based on different client's identity or scope, the service needs to run different conditional code. One way to achieve this functionality is to add a custom http-header in each WCF method call on client side, which will enable WCF service to identity the client for any given request.

In this exmaple, I will add a custom http-header named Client-Id, using custom implemenation of IClientMessageInspector interace.

You need to create two classes

  1. One is CustomHeaderEndpointBehavior to implment IEndpointBehavior interface.
  2. Second is CustomHeaderMessageInspector which implements the IClientMessageInspector interface.

The CustomHeaderEndpointBehavior class will add our custom CustomHeaderMessageInspector to ClientMessageInspectors collection for clientRuntime object.

clientRuntime.ClientMessageInspectors.Add(customHeaderMessageInspector);

In CustomHeaderMessageInspector class, we can add the custom header in BeforeSendRequest() method.

Complete code listing for CustomHeaderMessageInspector class is:

public class CustomHeaderMessageInspector : IClientMessageInspector
{
   private const string CLIENT_ID_HTTP_HEADER = "Client-Id";
   private string _clientId;

   public CustomHeaderMessageInspector(string clientId)
   {
      this._clientId = clientId;
   }

   public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, 
                                 object correlationState)
   {

   }

   public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, 
                                   System.ServiceModel.IClientChannel channel)
   {
      HttpRequestMessageProperty httpRequestMessage;
      object httpRequestMessageObject;
		
      if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name, 
                                         out httpRequestMessageObject))
      {
         httpRequestMessage = httpRequestMessageObject as HttpRequestMessageProperty;
         if (string.IsNullOrEmpty(httpRequestMessage.Headers[CLIENT_ID_HTTP_HEADER]))
         {
            httpRequestMessage.Headers[CLIENT_ID_HTTP_HEADER] = this._clientId;
         }
      }
      else
      {
         httpRequestMessage = new HttpRequestMessageProperty();
         httpRequestMessage.Headers.Add(CLIENT_ID_HTTP_HEADER, this._clientId);
         request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage);
      }

      return request;
   }
}

Code listing for CustomHeaderEndpointBehavior class is:

public class CustomHeaderEndpointBehavior : IEndpointBehavior
{
   private string _clientId;

   public CustomHeaderEndpointBehavior(string clientId)
   {
      this._clientId = clientId;
   }

   public void AddBindingParameters(ServiceEndpoint endpoint, 
               System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
   {

   }

   public void ApplyClientBehavior(ServiceEndpoint endpoint, 
               System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
   {
      CustomHeaderMessageInspector inspector = new CustomHeaderMessageInspector(this._clientId);

      clientRuntime.ClientMessageInspectors.Add(inspector);
   }

   public void ApplyDispatchBehavior(ServiceEndpoint endpoint, 
               System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
   {

   }

   public void Validate(ServiceEndpoint endpoint)
   {

   }
}

When calling the service methods on the client side, you can simply add the custom EndpointBehavior (CustomHeaderEndpointBehavior) on the service client instance object.

ServiceReference1.Service1Client service1Client = new ServiceReference1.Service1Client();

var requestInterceptor = new CustomHeaderEndpointBehavior();
service1Client.Endpoint.EndpointBehaviors.Add(requestInterceptor);

Now you can call any service method, the custom htpp-header will be automatically added to each request.

Related Post(s):

How to trace soap xml from Web Service client?

In this post I will explain how to trace the raw xml for each request and response sent between client/server for Soap/WCF Services.

I found this idea/code from stackoverflow post:

how to trace soap xml as a webservice client in netcore? .

You need to create two classes

  1. One is InspectorBehavior to implment IEndpointBehavior interface.
  2. Second is MyMessageInspector which implements the IClientMessageInspector interface.

The InspectorBehavior class will use the ApplyClientBehavior() method to add the real message inspector by calling Add() method on ClientMessageInspectors collection for clientRuntime object.

clientRuntime.ClientMessageInspectors.Add(myMessageInspector);

Further in MyMessageInspector class, we can retreive and save the Request and Response Xml content in local variables/properties in these two methods.

  • BeforeSendRequest
  • AfterReceiveReply

Complete code listing for MyMessageInspector class is:

public class MyMessageInspector : IClientMessageInspector
{
   public string LastRequestXML { get; private set; }
   public string LastResponseXML { get; private set; }

   public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, 
                                 object correlationState)
   {
      LastResponseXML = reply.ToString();
   }

   public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, 
                                   System.ServiceModel.IClientChannel channel)
   {
      LastRequestXML = request.ToString();
      return request;
   }
}

Code listing for InspectorBehavior class is:

public class InspectorBehavior : IEndpointBehavior
{
   public string LastRequestXML
   {
      get
      {
         return myMessageInspector.LastRequestXML;
      }
   }

   public string LastResponseXML
   {
      get
      {
         return myMessageInspector.LastResponseXML;
      }
   }

   private MyMessageInspector myMessageInspector = new MyMessageInspector();

   public void AddBindingParameters(ServiceEndpoint endpoint, 
               System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
   {

   }

   public void ApplyDispatchBehavior(ServiceEndpoint endpoint, 
               EndpointDispatcher endpointDispatcher)
   {

   }

   public void Validate(ServiceEndpoint endpoint)
   {

   }

   public void ApplyClientBehavior(ServiceEndpoint endpoint, 
               ClientRuntime clientRuntime)
   {
      clientRuntime.ClientMessageInspectors.Add(myMessageInspector);
   }
}

I used the WFC service instance created by Visual Studio template with default two methods GetData() and GetDataUsingDataContract();

When calling the service methods on the client side, you can simply add the custom EndpointBehavior (InspectorBehavior) on the service client instance object.

ServiceReference1.Service1Client service1Client = new ServiceReference1.Service1Client();

var requestInterceptor = new InspectorBehavior();
service1Client.Endpoint.EndpointBehaviors.Add(requestInterceptor);

After service method call, you can get the Request and Response Xml content by requestInterceptor's properties:

string str1 = service1Client.GetDataAsync(1).GetAwaiter().GetResult();
string req1Xml = requestInterceptor.LastRequestXML;
string res1Xml = requestInterceptor.LastResponseXML;

Here is the sample of raw sample I received by above call.

Request

<?xml version="1.0" encoding="utf-16"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none"
    >http://tempuri.org/IService1/GetData</Action>
  </s:Header>
  <s:Body>
    <GetData xmlns="http://tempuri.org/">
      <value>1</value>
    </GetData>
  </s:Body>
</s:Envelope>

Response

<?xml version="1.0" encoding="utf-16"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header />
  <s:Body>
    <GetDataResponse xmlns="http://tempuri.org/">
      <GetDataResult>You entered: 1</GetDataResult>
    </GetDataResponse>
  </s:Body>
</s:Envelope>

Call the second method, and get the Request and Response Xml content by same properties:

ServiceReference1.CompositeType compositeType = new ServiceReference1.CompositeType();
compositeType.BoolValue = true;
compositeType.StringValue = "some text";

ServiceReference1.CompositeType compositeTypeRes = 
       service1Client.GetDataUsingDataContractAsync(compositeType).GetAwaiter().GetResult();
string req2Xml = requestInterceptor.LastRequestXML;
string res2Xml = requestInterceptor.LastResponseXML;

Here is the sample of raw sample I received by above call.

Request

<?xml version="1.0" encoding="utf-16"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none"
    >http://tempuri.org/IService1/GetDataUsingDataContract</Action>
  </s:Header>
  <s:Body>
    <GetDataUsingDataContract xmlns="http://tempuri.org/">
      <composite xmlns:d4p1="http://schemas.datacontract.org/2004/07/WcfService1" 
      xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <d4p1:BoolValue>true</d4p1:BoolValue>
        <d4p1:StringValue>some text</d4p1:StringValue>
      </composite>
    </GetDataUsingDataContract>
  </s:Body>
</s:Envelope>

Response

<?xml version="1.0" encoding="utf-16"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header />
  <s:Body>
    <GetDataUsingDataContractResponse xmlns="http://tempuri.org/">
      <GetDataUsingDataContractResult xmlns:a="http://schemas.datacontract.org/2004/07/WcfService1" 
      xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <a:BoolValue>true</a:BoolValue>
        <a:StringValue>some textSuffix</a:StringValue>
      </GetDataUsingDataContractResult>
    </GetDataUsingDataContractResponse>
  </s:Body>
</s:Envelope>

References:

Related Post(s):

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):

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):

July 18, 2021

Dynamic where clause in Linq to Entities

Suppose you want to write Linq Query to filter the records by multiple parameters.

For example you have following method which will filter records based on the array of paramters specified.

public static List<Product> GetProducts(string[] params)
{
	var myQuery = from p in ctxt.Products
				select p;

	foreach(string param in params)
	{
	   myQuery = myQuery.Where(p => p.Description.Contains(param);
	}

	var prodResult = prod.ToList();

	return prodResult;
}

This query works fine if you need the AND concatenation of all parameter filters, you want to fetch records when all the paramters need to be statisfied.

What if you want to write the same query but with OR concatenation, as if any of the parameter is passed, it should return the records.

Here comes the PredicateBuilder by Pete Montgomery which will work with Linq-to-SQL and EntityFramework as well.

There is another PredicateBuilder by albahari , but it does not work well with EntityFramework.

You can use the following code for PredicateBuilder (copied from Pete Montgomery's post).

/// 
/// Enables the efficient, dynamic composition of query predicates.
/// 
public static class PredicateBuilder
{
    /// 
    /// Creates a predicate that evaluates to true.
    /// 
    public static Expression<Func<T, bool>> True<T>() { return param => true; }
 
    /// 
    /// Creates a predicate that evaluates to false.
    /// 
    public static Expression<Func<T, bool>> False<T>() { return param => false; }
 
    /// 
    /// Creates a predicate expression from the specified lambda expression.
    /// 
    public static Expression<Func<T, bool>> Create<T>(Expression<Func<T, bool>> predicate) { return predicate; }
 
    /// 
    /// Combines the first predicate with the second using the logical "and".
    /// 
    public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
    {
        return first.Compose(second, Expression.AndAlso);
    }
 
    /// 
    /// Combines the first predicate with the second using the logical "or".
    /// 
    public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
    {
        return first.Compose(second, Expression.OrElse);
    }
 
    /// 
    /// Negates the predicate.
    /// 
    public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> expression)
    {
        var negated = Expression.Not(expression.Body);
        return Expression.Lambda<Func<T, bool>>(negated, expression.Parameters);
    }
 
    /// 
    /// Combines the first expression with the second using the specified merge function.
    /// 
    static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
    {
        // zip parameters (map from parameters of second to parameters of first)
        var map = first.Parameters
            .Select((f, i) => new { f, s = second.Parameters[i] })
            .ToDictionary(p => p.s, p => p.f);
 
        // replace parameters in the second lambda expression with the parameters in the first
        var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
 
        // create a merged lambda expression with parameters from the first expression
        return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
    }
 
    class ParameterRebinder : ExpressionVisitor
    {
        readonly Dictionary<ParameterExpression, ParameterExpression> map;
 
        ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
        {
            this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
        }
 
        public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
        {
            return new ParameterRebinder(map).Visit(exp);
        }
 
        protected override Expression VisitParameter(ParameterExpression p)
        {
            ParameterExpression replacement;
 
            if (map.TryGetValue(p, out replacement))
            {
                p = replacement;
            }
 
            return base.VisitParameter(p);
        }
    }
}

This will provide extension methods that you can use to write your queries. Here is an example how to write the above query with OR concatenation.

public static List<Product> GetProducts(string[] params)
{
	var myQuery = from p in ctxt.Products
				select p;

	Expression<Func<Product, bool>> x = null;

	int i = 1;

	foreach(string param in params)
	{
	   if (i == )
	   {
	      x = L => L.Description.Contains(param);
	   }
	   else 
	   {
	      Expression<Func<Product, bool>> y = L => L.Description.Contains(param); 
	      x = x.Or(y); 
	   }

   	   i = i + 1;
	}

	myQuery = myQuery.Where(x); 
	
	var prodResult = myQuery.ToList();

	return prodResult;
}

References:

April 14, 2021

Use ClosedXML to write excel file

Office Open XML (also informally known as OOXML) is a zipped, XML-based file format developed by Microsoft for representing spreadsheets, charts, presentations and word processing documents. Starting with the 2007 Microsoft Office system, Microsoft Office uses the XML-based file formats, such as .docx, .xlsx, and .pptx representing Microsoft Word, Microsoft Excel, and Microsoft PowerPoint repectively.

The OpenXML specification is a large and complicated model to implement. Trying to implement this model by your own involves a lot of time and effort. Another option is to use ClosedXML (an open source library created based on OpenXmlSdk) for manipulate OpenXML format files.

ClosedXML is a .NET library for reading, manipulating and writing Excel 2007+ (.xlsx, .xlsm) files. Having user-friendly model, it makes it easier to deal with OpenXML API.

To install ClosedXML, run the following command in the Package Manager Console:

Install-Package ClosedXML

The most important point about ClosedXML is:

ClosedXML allows you to create Excel files without the Excel application. The typical example is creating Excel reports on a web server.

First you have to import the library for Excel classes:

using ClosedXML.Excel;

In the following code snippet, we are creating a new worksheet Sheet1 and writing the text Hello World! on the cell A1, then save the file as HelloWorld.xlsx:

using (var workbook = new XLWorkbook())
{
    var worksheet = workbook.Worksheets.Add("Sheet1");
    worksheet.Cell("A1").Value = "Hello World!";
    workbook.SaveAs("HelloWorld.xlsx");
}

Change the font for the whole sheet:

worksheet.Style.Font.FontName = "Calibri";

Change the font style and color for a particular cell:

worksheet.Cells("A1").Style.Font.FontSize = 14;
worksheet.Cells("A1").Style.Font.Bold = true;
worksheet.Cells("A1").Style.Font.FontColor = XLColor.White;

Select the range and fill background color:

var range1 = worksheet.Ranges("A1:A25,B1:B25");
range1.Style.Fill.BackgroundColor = XLColor.FromHtml("#556B2F");

Adjusts the width of all columns based on its contents.

worksheet.Columns().AdjustToContents();

These are few examples which demonstrates the basic functionality ClosedXML supports for Excel files.

For official project site and Nuget Package, please visit the github and nuget sites:

References(s):

January 29, 2021

Call WCF - Set SecurityProtocol & ServerCertificateValidationCallback

.Net Applications use ServicePointManager.SecurityProtocol Property to specify the version of the Secure Sockets Layer (SSL) or Transport Layer Security (TLS) protocol for new connections, existing connections aren't changed.

It is recommended that you should not specify this property manually and let it be use its default value, which will be obtained from machine configuration. Still In some scenarios, you may want to specifically define the SecurityProtocol when calling a WCF service with Https link. In this case you can define the required protocols like this:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
                   | SecurityProtocolType.Tls11
                   | SecurityProtocolType.Tls12
                   | SecurityProtocolType.Ssl3;

Since these are flags, so you can use bitwise OR(|) operator to specifiy multiple protocols if your connection requires.

Another property is ServerCertificateValidationCallback, which is used by the client to perform custom validation for the server certificate. The sender parameter passed to the RemoteCertificateValidationCallback can be a host string name or an object derived from WebRequest (HttpWebRequest, for example) depending on the CertificatePolicy property.

If you trust the server and not using custom validation, you can simply return true from the callback method.

 
ServicePointManager.ServerCertificateValidationCallback =
             new RemoteCertificateValidationCallback(IgnoreCertificateErrorHandler);

Here is the definition of IgnoreCertificateErrorHandler, which will always return true.

private static bool IgnoreCertificateErrorHandler(object sender,
   X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{​​​​​​​
	return true;
}​​​​​​​

You can also replace the above callback method definition with a short-hand delegate syntax.

ServicePointManager.ServerCertificateValidationCallback += delegate { return true; };

References:

January 23, 2021

When to set ServicePointManager.SecurityProtocol Property

When communicating with external services using TLS/SSL through APIs (such as HttpClient, HttpWebRequest, FTPClient, SmtpClient, SslStream), .Net application uses ServicePointManager.SecurityProtocol Property as the version of the Secure Sockets Layer (SSL) or Transport Layer Security (TLS) protocol for new connections, existing connections aren't changed.

Summary points

  • No default value is listed for this property for .Net Framework versions prior to 4.6.2.
  • Since default protocols and protection levels are changed over time in order to avoid known weaknesses. Therefore defaults vary depending on individual machine configuration, installed software, and applied patches.
  • When developing custom applications, avoid the assumption that a given security level is used by default. Only if you are sure that a particular application connection requires an specific security level (SSL/TLS) then you can explicitly specify the matching level in your code.

Review the following points for TLS support in different .Net Frameworks.

  • Starting with the .NET Framework 4.7, the default value of this property is SecurityProtocolType.SystemDefault. Which means the default security protocols from the operating system (or from any custom configurations performed by a system administrator) will be inherited by .NET Framework's networking APIs based on SslStream (such as FTP, HTTP, and SMTP).
  • For .NET 4.6 and above: Includes a new security feature that blocks insecure cipher and hashing algorithms for connections. TLS 1.2 is supported by default.
  • For .NET 4.5: TLS 1.2 is supported, but it’s not a default protocol. You need set manually. The following code will make TLS 1.2 default, make sure to execute it before making a connection to secured resource:
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
    
  • For .NET 4.0: TLS 1.2 is not supported, but if you have .NET 4.5 (or above) installed on the system then you still set for TLS 1.2 even if your application framework doesn’t support it. The problem is that SecurityProtocolType in .NET 4.0 doesn’t have an entry for TLS1.2, so you would have to use a numeric value and cast it to SecurityProtocolType enum:
        ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
    
  • For .NET 3.5 or below: TLS 1.2 is not supported. Upgrade your application to more recent version of the framework.

References:

December 24, 2020

dotnet-svcutil - Generate Proxy Code with namespace

dotnet-svcutil helps you generate WCF Client proxy code for target service, for example:

dotnet-svcutil https://localhost:8081/OrderManagement/OrderManagement.svc 
               -d "Connected Services/MyOrderManagementService"

In this command we have provided directory path where we want to generate the proxy code output. In this case we have the path Connected Services/MyOrderManagementService from current directory.

You may notice that in the output code, it will generate the namespace with similar name, i.e. namespace Connected_Services_MyOrderManagementService:

If you want to change the namespace, you can use n (namespace) parameter.

Using this command:

dotnet-svcutil https://localhost:8081/OrderManagement/OrderManagement.svc 
               -d "Connected Services/MyOrderManagementService"
               -n "*,MyNewNamespaceForOrderManagementService"

This time, the output code will contain the namespace MyNewNamespaceForOrderManagementService.

References:

Related Post(s):