Passing parameters to an anonymous method using an action in C# - c#

We are still having problems passing a parameter to an action. Here's what we have so far:
public ActionResult Create(string ds) {
HandleException(new Action<string, ref System.Web.Mvc.ModelState>(ds,ModelState) => {
InitializeServices(ds, "0000");
vm.Account = new Account {
PartitionKey = "0000",
RowKey = "0000",
Created = DateTime.Now,
CreatedBy = User.Identity.Name
};
});
return View("CreateEdit", vm);
}
private void HandleException(Action action) {
try {
action();
}
catch (ServiceException ex) {
ModelState.Merge(ex.Errors);
}
catch (Exception e)
{
Trace.Write(e);
ModelState.AddModelError("", "Database access error: " + e.Message);
}
}
This gives 12 syntax errors and most are pointing to the line:
HandleException(new Action<string,
We have also have syntax errors saying that "ref" is not the correct syntax

Generic types expect types as their parameters... So Action requires actual types for each argument. "ref Type" is not a type. Ref is just a keyword.
As Jakub suggests, you should remove "ref" altogether and mutate your ModelState

The argument of HandleException is of type Action, but you call it with an object of type Action<string, ref System.Web.Mvc.ModelState>, which is a specialization of Action<T1, T2>. These two types must be the same, just choose one of them.

public ActionResult Create(string ds) {
HandleException(() => {
InitializeServices(ds, "0000");
vm.Account = new Account {
PartitionKey = "0000",
RowKey = "0000",
Created = DateTime.Now,
CreatedBy = User.Identity.Name
};
});
return View("CreateEdit", vm);
}
private void HandleException(Action action) {
try {
action();
}
catch (ServiceException ex) {
ModelState.Merge(ex.Errors);
}
catch (Exception e)
{
Trace.Write(e);
ModelState.AddModelError("", "Database access error: " + e.Message);
}
}

Related

How to overwrite delegated parameters?

How to overwrite delegated parameters
I do have a service with a method like the below:
public static IEnumerable<IntegracaoParoquia> GetMyStuffFromRepo(MainForm form, Decimal myId)
{
IEnumerable<MyStuffClass> stuffCollection = null;
using (var unitOfWork = new UnitOfWork())
{
try
{
unitOfWork.OpenConnection();
stuffCollection = GetRepo().GetStuff(myId, unitOfWork.GetConnection(), unitOfWork.GetTransaction());
}
catch (Exception ex)
{
unitOfWork.Rollback();
LogError(form, ex);
}
}
return stuffCollection;
}
but since a can end with dozen call like this I want to wrap them in a generic call like the below:
private static R CallMyRepoMethod<P, R>(MainForm form, P param, Func<P, IDbConnection, IDbTransaction, R> method)
{
R result = default(R);
using (var unitOfWork = new UnitOfWork())
{
try
{
unitOfWork.OpenConnection();
result = method(param, unitOfWork.GetConnection(), unitOfWork.GetTransaction());
}
catch (Exception ex)
{
unitOfWork.Rollback();
LogError(form, ex);
}
}
return result;
}
public static IEnumerable<IntegracaoParoquia> GetMyStuffFromRepo(MainForm form, Decimal myId)
{
return CallMyRepoMethod<Decimal, IEnumerable<MyStuffClass>>(form, myId, (x,y,z)=>GetRepo().GetStuff(myId, null, null) );
}
The problem is: I want to keep the using inside my delegate (and the provided connection and transaction) but due to the repository method signature. When (x,y,z)=>GetRepo().GetStuff(myId, null, null) is called it passes the null values instead of using the correct values from the delegate.
That's reasonable if you consider the using is not in the scope outside the delegate.
There's any way to get around it or do I need to rewrite it using invoke?

Generic Function wrapper

I have many functions with different content but the parameters and try catch inside is almost similar. Is there anyway to wrap the function up so that can reduce redundant codes.
ResponseStatus GetPotatoList(GetPotatosRequest requestParam, out GetPotatosResponse response, out ResponseErrorType errorType)
{
ResponseStatus status = ResponseStatus.Fail;
response = new GetPotatosResponse();
//To Do
try
{
//To Do
status = ResponseStatus.Success;
}
catch(CustomException ex)
{
errorType = ResponseErrorType.CustomError;
}
catch(TimeoutException ex)
{
errorType = ResponseErrorType.Timeout;
}
catch(Exception ex)
{
errorType = ResponseErrorType.GeneralFailure;
}
return status;
}
You can pass an Action to your method.
ResponseStatus GetPotatoList(Action action1, Action action2, GetPotatosRequest requestParam, out GetPotatosResponse response, out ResponseErrorType errorType)
{
ResponseStatus status = ResponseStatus.Fail;
response = new GetPotatosResponse();
action1();
try
{
action2();
status = ResponseStatus.Success;
}
catch(CustomException ex)
{
errorType = ResponseErrorType.CustomError;
}
catch(TimeoutException ex)
{
errorType = ResponseErrorType.Timeout;
}
catch(Exception ex)
{
errorType = ResponseErrorType.GeneralFailure;
}
return status;
}
Then use it:
var response = GetPotatoList(
() => doSomething(),
() => doSomethingElse(),
requestParam,
out response,
out errorType);
I needed to provide functionality before and after invoking an original method whose signature didn't vary much.
I used Func<..>...
public static Func<string, string> Hello = name => "hello " + name;
public static string Hello2(string name) => wrap(Hello)(name);
// This does NOT retain the name of the arg for hints in the IDE
public static Func<string, string> Hello3 = name => wrap(Hello)(name);
private static Func<string, T> wrap<T>(Func<string, T> orig)
{
return name => orig(name.ToUpper());
}
Instead using Action you should maybe use a function that will take the request as the parameter and return your response object, then you can take benefit of generics to make the call and then handle specific cases. Also returning tuple or some generic type for the Result might be a good idea instead of using out parameters.
public static Tuple<TResponse, ResponseStatus, ResponseErrorType> GetResponse<TRequest, TResponse>(Func<TRequest, TResponse> action, TRequest request)
{
var status = ResponseStatus.Fail;
var errorType = ResponseErrorType.None;
var response = default(TResponse);
try
{
response = action(request);
status = ResponseStatus.Success;
}
catch (CustomException ex)
{
errorType = ResponseErrorType.CustomError;
}
catch (TimeoutException ex)
{
errorType = ResponseErrorType.Timeout;
}
catch (Exception ex)
{
errorType = ResponseErrorType.GeneralFailure;
}
return new Tuple<TResponse, ResponseStatus, ResponseErrorType>(response, status, errorType);
}

How to avoid code duplication inside two methods?

I have two identical methods, but one of them have return statement inside try catch
public void A(Guid agentId)
{
var agent = _agentsProvider.GetAgentById(agentId);
var updateCompletionSource = C(agentId);
try
{
var cacheEntry = UpdateAgentMetadataCacheEntry(agent, true, false);
updateCompletionSource.SetResult(cacheEntry);
}
catch (Exception e)
{
updateCompletionSource.SetException(e);
}
}
private Entry B(IAgent agent)
{
var updateCompletionSource = C(agent.Id);
try
{
var cacheEntry = UpdateAgentMetadataCacheEntry(agent, false, false);
updateCompletionSource.SetResult(cacheEntry);
return cacheEntry;
}
catch (Exception e)
{
updateCompletionSource.SetException(e);
return GetPreviousCacheEntry();
}
}
How to collect identical part and create new method with this part?
Unless GetPreviousCacheEntry could have problematic side-effects, it seems to me that you don't need method A at all.
Just call method B and ignore the return value if you're not interested in it.
As noted in comments, the methods aren't identical other than the return statements though - because they use a different second argument for UpdateAgentMetadataCacheEntry, and they have different parameters too (one has a Guid and one has an Agent). You could refactor this into:
private Entry B(IAgent agent, bool foo)
{
var updateCompletionSource = C(agent.Id);
try
{
var cacheEntry = UpdateAgentMetadataCacheEntry(agent, foo, false);
updateCompletionSource.SetResult(cacheEntry);
return cacheEntry;
}
catch (Exception e)
{
updateCompletionSource.SetException(e);
return GetPreviousCacheEntry();
}
}
... with a meaningful name for foo, obviously. I'll assume the difference in parameter type isn't a problem in reality.
Like Jon said, you don't need method A. Just add another parameter for boolean value.
public void A(Guid agentId)
{
var agent = _agentsProvider.GetAgentById(agentId);
AnotherA(agent, true);
}
private Entry B(IAgent agent)
{
return AnotherA(agent, false);
}
private Entry AnotherA(IAgent agent, bool a)
{
try
{
var cacheEntry = UpdateAgentMetadataCacheEntry(agent, a, false);
updateCompletionSource.SetResult(cacheEntry);
return cacheEntry;
}
catch (Exception e)
{
updateCompletionSource.SetException(e);
return GetPreviousCacheEntry();
}
}

Repeating code pattern

I have certain code pattern (which log performance and other variable for each function) which need to be present in every function, and I do not want to repeat the code over and over again. Here is what the code looks like:
public OutClass FUNC-X
{
if (IsDebugEnabled)
{
Logger("Start DataLibrary: FUNC-X");
}
try
{
CheckInitSucceeded();
GetAuthenticationTokens();
var dm = new Manager();
/**
* THIS SINGLE LINE IS THE VARIABLE PART
**/
var output = dm.FUNC-X(...);
if (IsDebugEnabled)
{
var data = Serialize(output);
Logger(output);
}
return output;
}
catch (WebFaultException)
{
throw;
}
catch (OtherException ex)
{
if (Logger.IsErrorEnabled)
{
Logger.LogError("Exception in FUNC-X", ex);
}
throw new OtherException("Some Message");
}
catch (Exception ex)
{
if (IsErrorEnabled)
{
Logger("Exception in FUNC-X", ex);
}
throw new Exception("Generic Exception");
}
finally
{
if (IsDebugEnabled)
{
Logger("End FUNC-X");
}
}
}
Essentially, I just need to replace FUNC-X with FUNC-Y or FUNC-Z everywhere this name occurs, is there some kind of design pattern which I can follow?
I'm sorry if the question is vague, I shall be happy to provide any details you ask.
Yeah, there are many ways to provide nice log code.
Use aspect-oriented programming. There is PostSharp and Spring.NET. You can use log4net library. All of them after config supports writing of method name.
You can use T4 and generate code for all funcs before compile.
You can write one global logging method that accepts Func<object> method and string methodName. Suppose you named your logging method LogAndExecute. Then to call you must write smth like:
LogAndExecute("func-x", () => dm.Func-X(/*your args*/))
If you got problems with different different return types of your funcs, use generics
You can use simple delegate to accept the variable part as parameter (if no. of parameters to function call in single line are same)
public void Function_X(Func<object,..> func)
{
if (IsDebugEnabled)
{
Logger("Start DataLibrary: FUNC-X");
}
try
{
CheckInitSucceeded();
GetAuthenticationTokens();
var dm = new Manager();
/**
* THIS SINGLE LINE IS THE VARIABLE PART
**/
// var output = dm.FUNC-X(...);
var output = func(...);
if (IsDebugEnabled)
{
var data = Serialize(output);
Logger(output);
}
return output;
}
catch (WebFaultException)
{
throw;
}
catch (OtherException ex)
{
if (Logger.IsErrorEnabled)
{
Logger.LogError("Exception in FUNC-X", ex);
}
throw new OtherException("Some Message");
}
catch (Exception ex)
{
if (IsErrorEnabled)
{
Logger("Exception in FUNC-X", ex);
}
throw new Exception("Generic Exception");
}
finally
{
if (IsDebugEnabled)
{
Logger("End FUNC-X");
}
}
}
You can create a common function that accepts a Func delegate:
static public TOutClass CommonFunc<TOutClass>(Func<Manager, TOutClass> func)
{
if (IsDebugEnabled)
{
Logger("Start DataLibrary: FUNC-X");
}
try
{
CheckInitSucceeded();
GetAuthenticationTokens();
var dm = new Manager();
TOutClass output = func(dm);
if (IsDebugEnabled)
{
var data = Serialize(output);
Logger(output);
}
return output;
}
catch
[...]
}
Your would write your functions as:
public OutClass FUNC-X(...)
{
return CommonFunc(dm=>dm.FUNC-X(...));
}

Passing parameters into an Action?

I am trying to fully understand how I can simplify the following:
public ActionResult Create(string ds) {
InitializeServices(ds, "0000");
vm.Account = new Account {
PartitionKey = "0000",
RowKey = "0000",
Created = DateTime.Now,
CreatedBy = User.Identity.Name
};
}
catch (ServiceException ex) {
ModelState.Merge(ex.Errors);
}
catch (Exception e) {
Trace.Write(e);
ModelState.AddModelError("", "Database access error: " + e.Message);
}
return View("CreateEdit", vm);
}
I had a few great answers and the following was suggested:
private void HandleException(Action action) {
try {
action();
}
catch (ServiceException ex) {
ModelState.Merge(ex.Errors);
}
catch (Exception e)
{
Trace.Write(e);
ModelState.AddModelError("", "Database access error: " + e.Message);
}
}
RunAndHandleExceptions(new Action(() =>
{
//Do some computing }
));
This looks like a really great solution but I still don't understand how I can pass in my
parameters into the action. What I need to do is to pass in the following:
string ds
System.Web.Mvc.ModelState ModelState (passed as a reference)
Just
HandleException(() => someFunction(ds, ModeState));
should do it
To get the return value, you need a Func<>, not Action<>:
private TR HandleException<TR>(Func<TR> action)
{
try
{
return action();
}
catch (ServiceException ex)
{
ModelState.Merge(ex.Errors);
}
catch (Exception e)
{
Trace.Write(e);
ModelState.AddModelError("", "Database access error: " + e.Message);
}
return default(TR); // null for reference types
}
You then would use it, e.g. without an existing function:
bool result = HandleException(() =>
{
if (string.IsNullOrEmpty(ds))
return false;
// do interesting stuff that throws many kinds of exceptions :)
// Note: freely use ds and ModelState from surrounding scope,
// no need to 'pass them'
return true;
});
Have you looked at RedirectToAction?
return this.RedirectToAction(c => c.SomeAction(MyParam));
You can define an action with up to 16 parameters (no discussion, if that number is useful, please). So, sour call could look like:
private void HandleException(Action<string, System.Web.Mvc.ModelState ModelState > action) {
Edit
Here is an example with an action having parameter:
private void RunHandleException(Action<int> action)
{
action(someIntValue);
}
...
RunAndHandleExceptions((someInt) =>
{
//Do some computing
});
And here is an example with a function having a return value:
private void RunHandleException(Func<bool, int> action)
{
bool returnValue = action(someIntValue);
}
...
RunAndHandleExceptions((someInt) =>
{
//Do some computing
return true;
});

Categories

Resources