In this article, I will show you a scenario where you can use delegates in c#.
Let’s say you have an application where you are doing communication with the database. Either using Entity Framework or Ado.Net. You will have to use try-catch for exception handling. Because you never know what error might occur in the database or the database stops working altogether.
If you are working on a web project then you can define global filter. But in most projects, there are multiple layers like business logic and repository layer. These layers are separate class library projects so any exception that occurs in these projects will not be detected by the global filter defined in a web project.
That is why you will have to define try-catch blocks in all your methods where you are communicating with the database.
Now defining try-catch block in every method will lead to repetition of code. To solve this problem you can use C# delegates. You can pass the code where you are actually communicating with the database to a common method using delegate and execute it there.
You can define try-catch block in that common method and catch all the exceptions that can come. In this way, you only have to write one try-catch block for all methods.
Practical Demo for C# delegates
Suppose you have 3 layers in your project UI Layer, Business logic or Service layer, and Data Access or repository layer.
In your repository layer, you will define a base class where you will write a common method to execute your delegate. Inherit all your repository layer classes with that base class.
In this article, I will show you execution of delegates using both Entity framework and Ado.Net.
using C# delegate with Entity Framework
Create a base class in your repository layer and add the following method to it. This method will be used to communicate with the database using Entity framework.
This is a generic method in which
1) First parameter is an instance of context class of Entity framework.
2) Second parameter is a generic delegate which we will pass from our repository method. You can learn more about generic delegates from here.
3) Third parameter is the object which needs to be saved in the database.
I have defined possible exceptions that can occur while communication with the database.
protected DBContextResult<U> ExecuteEntityFrameworkMethod<T, U>(DelegateDemoContext db, Func<DelegateDemoContext, T, U> Func, T Obj)
{
try
{
return new DBContextResult<U>
{
Data = Func(db, Obj),
TransactionResult = true
};
}
catch (DbUpdateException ex)
{
//Log error
return new DBContextResult<U>
{
TransactionResult = false
};
}
catch (SqlException ex)
{
//Log error
return new DBContextResult<U>
{
TransactionResult = false
};
}
catch (Exception ex)
{
//Log error
return new DBContextResult<U>
{
TransactionResult = false
};
}
}
using C# delegate with Ado.Net
The following method will be used to communicate with the database using Ado.Net.
This is also a generic method in which
1) First parameter is the DataAdapter object
2) Second parameter is a generic delegate which we will pass from the repository method.
Possible Exceptions are defined that can occur while communication with the database.
protected DBContextResult<U> ExecuteAdoNetMethod<T, U>(T obj, Func<T, U> Func)
{
try
{
return new DBContextResult<U>
{
Data = Func(obj),
TransactionResult = true
};
}
catch (SqlException ex)
{
//Log error
return new DBContextResult<U>
{
TransactionResult = false
};
}
catch (Exception ex)
{
//log error
return new DBContextResult<U>
{
TransactionResult = false
};
}
}
}
Final Base repository class looks like this.
using DelegateDemo.Models;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace DelegateDemo.Utilities.Repository
{
public abstract class BaseRepository
{
protected DBContextResult<U> ExecuteEntityFrameworkMethod<T, U>(DelegateDemoContext db, Func<DelegateDemoContext, T, U> Func, T Obj)
{
try
{
return new DBContextResult<U>
{
Data = Func(db, Obj),
TransactionResult = true
};
}
catch (DbUpdateException ex)
{
//Log error
return new DBContextResult<U>
{
TransactionResult = false
};
}
catch (SqlException ex)
{
//Log error
return new DBContextResult<U>
{
TransactionResult = false
};
}
catch (Exception ex)
{
//Log error
return new DBContextResult<U>
{
TransactionResult = false
};
}
}
protected DBContextResult<U> ExecuteAdoNetMethod<T, U>(T obj, Func<T, U> Func)
{
try
{
return new DBContextResult<U>
{
Data = Func(obj),
TransactionResult = true
};
}
catch (SqlException ex)
{
//Log error
return new DBContextResult<U>
{
TransactionResult = false
};
}
catch (Exception ex)
{
//log error
return new DBContextResult<U>
{
TransactionResult = false
};
}
}
}
}
Calling base repository method and passing C# delegate
1) Using Entity Framework
The following method shows you how to call a method of your base class and pass delegate. This method can be used when you are using Entity Framework.
In this method, we are calling our base class Entity Framework method and passing our context class object. We are also passing Entity object to be saved to the database.
public DBContextResult<MstUser> AddUserUsingEF(MstUser p_MST_User)
{
return ExecuteEntityFrameworkMethod<MstUser, MstUser>(db, (DataContext, P_MST_UserInfo) =>
{
DataContext.MstUsers.Add(P_MST_UserInfo);
DataContext.SaveChanges();
return p_MST_User;
}, p_MST_User);
}
2) Using Ado.net
Use the following method when you are using Ado.net. In this method, we are building a SqlDataAdapter object and passing it to the base class method and to be passed to delegate.
public DBContextResult<DataTable> AddUserUsingAdoNet(MstUser p_MST_User)
{
using SqlConnection conn = new SqlConnection("Server=DESKTOP-2KLD6BE;Database=DelegateDemo;User ID=Admin;pwd=admin123");
conn.Open();
using SqlCommand cmd = new SqlCommand("usp_AddUser", conn);
cmd.Parameters.Add(new SqlParameter("@FirstName", p_MST_User.FirstName));
cmd.Parameters.Add(new SqlParameter("@LastName", p_MST_User.LastName));
cmd.Parameters.Add(new SqlParameter("@MobileNumber", p_MST_User.MobileNumber));
using var da = new SqlDataAdapter(cmd);
cmd.CommandType = CommandType.StoredProcedure;
DBContextResult<DataTable> result = ExecuteAdoNetMethod<SqlDataAdapter, DataTable>(da, (DataAdapter) =>
{
DataTable DataTable = new DataTable();
da.Fill(DataTable);
return DataTable;
});
conn.Close();
return result;
}
Final Repository class looks like this
using DelegateDemo.Models;
using Microsoft.Data.SqlClient;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
namespace DelegateDemo.Utilities.Repository
{
public interface IUserRepository
{
DBContextResult<MstUser> AddUserUsingEF(MstUser p_MST_User);
DBContextResult<DataTable> AddUserUsingAdoNet(MstUser p_MST_User);
}
public class UserRepository : BaseRepository, IUserRepository
{
private DelegateDemoContext db;
public UserRepository()
{
db = new DelegateDemoContext();
}
public DBContextResult<MstUser> AddUserUsingEF(MstUser p_MST_User)
{
return ExecuteEntityFrameworkMethod<MstUser, MstUser>(db, (DataContext, P_MST_UserInfo) =>
{
DataContext.MstUsers.Add(P_MST_UserInfo);
DataContext.SaveChanges();
return p_MST_User;
}, p_MST_User);
}
public DBContextResult<DataTable> AddUserUsingAdoNet(MstUser p_MST_User)
{
using SqlConnection conn = new SqlConnection("Server=DESKTOP-2KLD6BE;Database=DelegateDemo;User ID=Admin;pwd=admin123");
conn.Open();
using SqlCommand cmd = new SqlCommand("usp_AddUser", conn);
cmd.Parameters.Add(new SqlParameter("@FirstName", p_MST_User.FirstName));
cmd.Parameters.Add(new SqlParameter("@LastName", p_MST_User.LastName));
cmd.Parameters.Add(new SqlParameter("@MobileNumber", p_MST_User.MobileNumber));
using var da = new SqlDataAdapter(cmd);
cmd.CommandType = CommandType.StoredProcedure;
DBContextResult<DataTable> result = ExecuteAdoNetMethod<SqlDataAdapter, DataTable>(da, (DataAdapter) =>
{
DataTable DataTable = new DataTable();
da.Fill(DataTable);
return DataTable;
});
conn.Close();
return result;
}
public void Dispose()
{
db.Dispose();
}
~UserRepository()
{
Dispose();
}
}
}
I have created a Github repository where I have used the above-shown methods. It is a Dotnet Core MVC project. check it out at https://github.com/juzer-hakimji/DelegateDemo.
You can download the SQL Server database from here.
Thank you for reading this article. Have a good day.
Share :
Hi,
Hope you liked the post, Thanks for reading 🙂