Avoid code repetition in c# - by using generics? - c#

I have following code in controller code:
public async Task<int> PullClientsAsync()
{
var service = new DesktopConnectorService<ClientModel>(
new WapiRepository<ClientModel>(), new QuickBooksRepository<ClientModel>());
var filter = new ClientSearchFilter();
try
{
var items = await service.GetItemsAsync(filter);
return items.Count;
}
catch (Exception ex)
{
}
return 0;
}
public async Task<int> PullInvoicesAsync()
{
var service = new DesktopConnectorService<InvoiceModel>(
new WapiRepository<InvoiceModel>(), new QuickBooksRepository<InvoiceModel>());
var filter = new InvoicesSearchFilter();
try
{
var items = await service.GetItemsAsync(filter);
return items.Count;
}
catch (Exception ex)
{
}
return 0;
}
public async Task<int> PullPaymentsAsync()
{
var service = new DesktopConnectorService<PaymentModel>(
new WapiRepository<PaymentModel>(), new QuickBooksRepository<PaymentModel>());
var filter = new PaymentSearchFilter();
try
{
var items = await service.GetItemsAsync(filter);
return items.Count;
}
catch (Exception ex)
{
}
return 0;
}
As you can see it is all about three types (ClientModel, PaymentModel and Invoices model). Lots of code above is repeating.
But I believe that it could be simplified. Any idea how to achieve that?
Thanks

If all models and filters share a common interface / base class, you can do:
public async Task<int> PullAsync<TModel, TFilter>()
where TModel : IModel,
where TFilter : IFilter, new();
{
var service = new DesktopConnectorService<TModel>(
new WapiRepository<TModel>(), new QuickBooksRepository<TModel>());
var filter = new TFilter();
try
{
var items = await service.GetItemsAsync(filter);
return items.Count;
}
catch (Exception ex)
{
}
return 0;
}
Side note - Don't use empty catch blocks like that, they swallow exceptions, making it very difficult to diagnose problems which may occur at a later point in time. At least have a logging statement in there, or do something meaningful. Otherwise, I'd remove it.

Related

ASP.NET Core - call one controller method from another

I need to call from create method delete for cleanup. I want to call DeleteDevice like lazy cleanup and do not care if it will succeed or not.
People suggested to use this way:
DeleteDevice(param).ConfigureAwait(false);
Is it safe?
public async Task<ActionResult<Device>> CreateDevice([FromBody] CreateDeviceRequest request)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
try
{
var registeredDevice = await RegisterDevice(request.DisplayName);
bool isCreatePrinterSucceed = false;
try
{
var updatedDevice = await UpdateDevice(registeredDevice.Id);
isCreatePrinterSucceed = true;
return Ok(new DeviceReference
{
DisplayName = request.DisplayName,
Id = updatedDevice.Id
});
}
finally
{
if (!isCreatePrinterSucceed)
{
var param = new DeleteDeviceRequest()
{
Id = registeredDevice.Id,
AzureUserBearerToken = request.AzureUserBearerToken
};
DeleteDevice(param).ConfigureAwait(false); ;
}
}
}
catch (Exception ex)
{
return StatusCode((int)HttpStatusCode.InternalServerError, ex.Message);
}
}

How to properly catch exceptions in multiple async method calls?

I have some async method:
public async Task<Object> MethodAsync()
{
return await MakeHttpRequestAsync();
}
I need to make multiple calls of this method. One of them can throw an exception. But I need to keep all possible returned Objects from other method calls that succeeded.
Option 1:
Task t1 = MethodAsync();
Task t2 = MethodAsync();
try
{
Task.WaitAll(new Task[]{t1,t2});
}
catch(Exception e)
{
...
}
//are t1 and t2 finished execution here with success or exception?
Option 2:
Task t1 = MethodAsync();
Task t2 = MethodAsync();
try
{
t1.Wait()
}
catch(Exception e)
{
...
}
try
{
t2.Wait()
}
catch(Exception e)
{
...
}
//what happens if t2 throws exception before t1 finished?
Any other options?
edit:
Thought about third option:
public async Task<Tuple<Object, Object>> MultipleAsyncCallsAsync(some arguments)
{
Object result1 = null, result2 = null;
try
{
result1 = await MethodAsync();
}
catch(Exception e)
{
}
try
{
result2 = await MethodAsync();
}
catch (Exception e)
{
}
return Tuple.Create(result1, result2);
}
edit #2:
Looks like third option is not working, but it's working this way:
public async Task<Tuple<object, object>> MultipleAsyncCallsAsync(some arguments)
{
object result1 = null, result2 = null;
Task<object> t1 = null, t2 = null;
t1 = Task.Run(()=> MethodAsync());
t2 = Task.Run(()=> MethodAsync());
try
{
result1 = await t1;
}
catch(Exception e)
{
}
try
{
result2 = await t2;
}
catch (Exception e)
{
}
return Tuple.Create(result1, result2);
}
Put the tasks in an array and inspect their status like this:
var t1 = MethodAsync();
var t2 = MethodAsync();
var tasks = new[] {t1, t2};
try
{
await Task.WhenAll(tasks);
}
catch
{
var failedTasks = tasks.Where(t => t.IsFaulted);
var allExceptions = failedTasks.Select(t => t.Exception?.Flatten());
}
var results = tasks.Where(t => t.IsCompletedSuccessfully).Select(t => t.Result);
What is does is it awaits all tasks and then uses the task status (using IsCompletedSuccessfully ect.) to get the results of all the tasks that did complete succesfully.
You can determine the failed tasks using IsFaulted and get their exception using the tasks Exception property.
If you want to catch/inspect the exception before the call to Task.WhenAll(..) is completed wrap the code inside MethodAsync in a try/catch:
public async Task<Object> MethodAsync()
{
try
{
..
}
catch(Exception ex)
{
//handle or throw
return null;
}
}
Or, if you cannot modify MethodAsync for some reason, you can wrap the method in a try/catch using this:
Func<Task<Object>, Task<Object>> TryExecute = new Func<Task<Object>, Task<object>>(async t =>
{
try
{
return await t;
}
catch (Exception ex)
{
//handle exception
return null;
}
});
and use it like this:
var t1 = TryExecute(MethodAsync());
var t2 = TryExecute(MethodAsyncF());
var tasks = new[] {t1, t2};
await Task.WhenAll(tasks);
Whenever there's a question about this kind of procedure ("call n methods, (a)wait for them all to complete, and then retrieve the results for each method and do something with them"), a better solution is almost always to create a higher-order method.
For example, if you want to do some kind of logging or something but otherwise ignore exceptions, then you can create a higher-order method like this:
public async Task<T> LogAndIgnoreExceptions(Task<T> task) where T : class
{
try
{
return await task;
}
catch (Exception ex)
{
Log(ex);
return null;
}
}
Then you can use Task.WhenAll in a very natural way:
var results = await Task.WhenAll(
LogAndIgnoreExceptions(MethodAsync()),
LogAndIgnoreExceptions(MethodAsync())
);
if (results[0] is not null)
{
T result = results[0];
}
else
{
// First call had an error.
}
Or, if you want to preserve the exception details and results, what you want is a little helper type like Try to enable railway programming:
var results = await Task.WhenAll(
Try.Create(MethodAsync()),
Try.Create(MethodAsync())
);
if (results[0].IsValue)
{
T result = results[0].Value;
}
else
{
Exception exception = results[0].Exception;
}

How to avoid duplicate "using" code

I have a wcf api and wish to wrap all requests inside a transaction
Currently my code looks like this in each endpoint
public MyCompleteList ReadOrganisations()
{
MyCompleteList resp = new MyCompleteList ();
try
{
using (TransactionScope scope = new TransactionScope())
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
DC_Base browser_request = new DC_Base(PROJECT);
browser_request.cmd_user_id = coreDb.GetUserIDFromLoginName(PROJECT,
HttpContext.Current.User.Identity.Name);
resp =
new MyCompleteList (coreSc.User_Read_All_Organisations(browser_request, utils,
validation, coreSc, coreDb));
scope.Complete();
}
else
{
resp.SetResponseNotLoggedIn();
}
}
}
catch (TransactionAbortedException ex)
{
resp.SetResponseServerError();
}
catch (ApplicationException ex)
{
resp.SetResponseServerError();
}
return resp;
}
As you can see if I am to use the "using" transaction scope part in every endpoint (approx 300) its going to be a lot of duplicated code.
is there anyway to reduce the amount of duplication?
You can write a helper method, that handles the transaction logic while calling your actual code as a lambda.
public static T Execute<T>(Func<T> func, TransactionExecutionOptions options = null)
{
options = options ?? TransactionExecutionOptions.Default;
T res;
using (var tx = new TransactionScope(options))
{
res = func();
tx.Complete();
}
return res;
}
Depending on your needs you can provide additional arguments to the Func argument; for example, the Execute method could also open a database connection and pass that to the func (then having Func<IDbConnection, T> as parameter type). YMMV.
For your example:
public MyCompleteList ReadOrganisations()
{
MyCompleteList resp = new MyCompleteList ();
try
{
resp = Execute(() => {
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
DC_Base browser_request = new DC_Base(PROJECT);
browser_request.cmd_user_id = coreDb.GetUserIDFromLoginName(PROJECT,
HttpContext.Current.User.Identity.Name);
resp =
new MyCompleteList (coreSc.User_Read_All_Organisations(browser_request, utils,
validation, coreSc, coreDb));
scope.Complete();
}
else
{
resp.SetResponseNotLoggedIn();
}
});
}
catch (TransactionAbortedException ex)
{
resp.SetResponseServerError();
}
catch (ApplicationException ex)
{
resp.SetResponseServerError();
}
return resp;
}
If possible, you can also factor the SetResponse*() methods out into a base class or interface (say IMyResponse), thus making it possible to handle this aspect inside the Execute method as well.
public static T Execute<T>(Func<T> func, TransactionExecutionOptions options = null) where T : IMyResponse
{
options = options ?? TransactionExecutionOptions.Default;
T res;
try
{
using (var tx = new TransactionScope(options))
{
res = func();
tx.Complete();
}
}
catch (TransactionAbortedException ex)
{
res.SetResponseServerError();
}
catch (ApplicationException ex)
{
res.SetResponseServerError();
}
return res;
}
1- Create a ServiceBase class as follows
public class ServiceBase
{
protected void ExecuteOperation(Action codetoExecute)
{
try
{
using (TransactionScope scope = new TransactionScope())
{
codetoExecute.Invoke();
scope.Complete();
}
}
catch (TransactionAbortedException ex)
{
// handle exception
}
catch (ApplicationException ex)
{
// handle exception
}
}
}
2- Each new service must inherits from ServiceBase and call ExecuteOperation instead. Code as follows:
ExecuteOperation(() =>
{
// Custom code here
});
3- Atomic transactions are useful when executing operations that dont expect results in return.

Asp Mvc 5 Async/Await Issue

public async Task<ActionResult> Index()
{
var service = new CoreServiceFactory().GetImpersonatingService();
try
{
var data = new Impersonation()
{
ImpersonatingId = "dac733c3-01ad-447b-b0df-3a7c21fef90b",
UserId = "dac733c3-01ad-447b-b0df-3a7c21fef90b"
};
var imp = await service.Add(data);
}catch(Exception ex) { throw ex; }
return View();
}
Above is one of my controllers action method. And this works fine when the insertion is successful. This should fail if the data already exists in database(unique constraints). So when i intentionally try to make it fail(i manually add the same record in the db and then try to add it again via this action method) the action method goes into a loop or something, the exception is never thrown , chrome keeps me showing me the loading icon , looks like it went into some deadlock state. Can someone please help me understand why it goes into deadlock state when exception is thrown and how can i handle it?
Below are the reference methods
service.Add(data)
public async Task<Impersonation> Add(Impersonation t)
{
if (ValidateData(t))
{
using (var uow = GetUnitOfWork())
{
var r = GetRepository(uow);
var item = r.Add(t);
try
{
var ret = await uow.Save();
if (ret > 0)
{
return item;
}
else
{
return null;
}
}
catch (Exception ex)
{
throw ex;
}
}
}
else
{
throw new ValidationException(null, "error");
}
}
uow.Save()
public class BaseUnitOfWork : IUnitOfWork
{
public DbContext _Context { get; private set; }
public BaseUnitOfWork(DbContext context)
{
this._Context = context;
}
public async Task<int> Save()
{
try
{
var ret = await this._Context.SaveChangesAsync();
return ret;
}catch(Exception ex)
{
throw ex;
}
}
}
Here is my suggestion: in uow.Save, log the error in the catch block and return zero (do not throw any exceptions).
public class BaseUnitOfWork : IUnitOfWork
{
public DbContext _Context { get; private set; }
public BaseUnitOfWork(DbContext context)
{
this._Context = context;
}
public async Task<int> Save()
{
try
{
var ret = await this._Context.SaveChangesAsync();
return ret;
}catch(Exception ex)
{
// log the error here
return 0;
}
}
}
I'm not sure if returning the null in the Add service is a good idea or not, you might need to handle that differently too.

Need to wrap functions in a standard try/catch function in c#

I know there are lots of delegate/func examples but I can't find any examples that will work for me, or I just don't understand them.
I'm using asp.net MVC for a website, and the website needs some web service calls for an outside application to interact with my app. These all need a function to execute (going to db and whatnot), and return a similar data model every time. I want to wrap each call in a try/catch and populate the model.
Here is the generic code that happens every call.
var model = new ResponseDataModel();
try
{
//execute different code here
}
catch (Exception ex)
{
model.Error = true;
model.Message = ex.ToString();
}
return View(model); // will return JSON or XML depending on what the caller specifies
This is one of the controller methods/ functions that I am using
public ActionResult MillRequestCoil()
{
var model = new ResponseDataModel();
try
{
/* edit */
//specific code
string coilId = "CC12345";
//additional code
model.Data = dataRepository.doSomethingToCoil(coilId);
//replaced code
//model.Data = new { Coil = coilId, M3 = "m3 message", M5 = "m5 message" };
model.Message = string.Format("Coil {0} sent successfully", coilId);
}
catch (Exception ex)
{
model.Error = true;
model.Message = ex.ToString();
}
return View(model);
}
I would like to be able to somehow convert the specific function to a variable to pass into the generic code. I've looked at delegates and anonymous funcs but it's pretty confusing until you do it yourself.
Put the following somewhere accessible:
public static ActionResult SafeViewFromModel(
Action<ResponseDataModel> setUpModel)
{
var model = new ResponseDataModel();
try
{
setUpModel(model);
}
catch (Exception ex)
{
model.Error = true;
model.Message = ex.ToString();
}
return View(model);
}
and then call it like:
public ActionResult MillRequestCoil()
{
return MyHelperClass.SafeViewFromModel(model =>
{
string coilId = "CC12345";
model.Data = new {
Coil = coilId,
M3 = "m3 message",
M5 = "m5 message" };
model.Message = string.Format("Coil {0} sent successfully", coilId);
});
}
public interface IAction{
public void doAction(ResponseDataModel model);
}
public class Action1 : IAction
{
public void doAction(ResponseDataModel model)
{
string coilId = "CC12345";
model.Data = new { Coil = coilId, M3 = "m3 message", M5 = "m5 message" };
model.Message = string.Format("Coil {0} sent successfully", coilId);
}
}
class Class1
{
public ActionResult MillRequestCoil(IAction action)
{
var model = new ResponseDataModel();
try
{
//specific code
action.doAction(model);
}
catch (Exception ex)
{
model.Error = true;
model.Message = ex.ToString();
}
return View(model);
}
}
Use:
var result = MillRequestCoil(new Action1());
or execute other code
var result = MillRequestCoil(new ActionXY());
This is a variation of Rawling's answer, that I believe has better readability:
public ActionResult MillRequestCoil()
{
var model = CreateResponseDataModel(RunSpecificCode);
return View(model);
}
public ActionResult MillDoSomethingElse ()
{
var model = CreateResponseDataModel(RunOtherCode);
return View(model);
}
private ResponseDataModel CreateResponseDataModel(Action<ResponseDataModel> action)
{
var model = new ResponseDataModel();
try
{
action(model);
}
catch (Exception ex)
{
model.Error = true;
model.Message = ex.ToString();
}
return model;
}
private void RunSpecificCode(ResponseDataModel model)
{
/* edit */
//specific code
const string coilId = "CC12345";
//additional code
model.Data = _dataRepository.DoSomethingToCoil(coilId);
//replaced code
//model.Data = new { Coil = coilId, M3 = "m3 message", M5 = "m5 message" };
model.Message = string.Format("Coil {0} sent successfully", coilId);
}
private void RunOtherCode(ResponseDataModel obj)
{
// some other piece of code
}
No lambdas, and nice separation of concerns between your specific code and the template code for the try/catch and model building stuff.

Categories