MatthiasVC
MatthiasVC

Reputation: 3

Assign passed functions result to object with variable type in C#

For an integration I'm running as a service once a day, I need to assign the result of API-calls to local variables. However, those API's might at any time decide to throw a 401 error, in which case I just want to try again, up to three times. I've got a functioning code to do that:

List<APIEntityProject> projectList = null;

private bool SetProjectList(){
    const maxRetries = 3;
    const RetryPause = 3000;
    int retries = 0;
    do
    {
        try
        {
            projectList = ProjApi.GetProject(activeWorkspace.WorkspaceCode);
        }
        catch (ApiException e)
        {
            if (e.ErrorCode == 401) // Unauthorized error (e.g. user doesn't have access to this Workspace
            {
                Log.Warning("Unauthorized error while fetching projects from Workspace, try {retries}",retries);
                retries++;
                System.Threading.Thread.Sleep(RetryPause * retries);//Waits 3 and then 6 seconds before retrying.
            }
            else throw;
        }
    } while (projectList == null || retries < maxRetries);
    if (retries == maxRetries)
    {
        Log.Error("An error has occured while trying to retrieve affected Projects, skipped document");
        errorCount++;
        return false;
    }
    return true;
}

But unfortunately I need to replicate this Logic so often I would like to use it in a function e.g. RetryNTimes (similar to This Solution

List<APIEntityProject> projectList = null;
List<APIEntityWBS> WBSList = null;
List<APIEntitySopeItem> SIList = null;
List<APIEntityScopeAsignment> SAList = null;
List<APIEntityActivity> ActList = null;
...

RetryNTimes(projectList,ProjApi.GetProject(activeWorkspace.WorkspaceCode),3,3000,"ProjectList");
RetryNTimes(WBSList, WBSApi.GetAllWBS(activeProject.ProjectID),3,3000,"WBSList");
RetryNTimes(SIList, SIApi.GetAllScopeItems(activeProject.ProjectID),3,3000,"ScopeItemsList");
RetryNTimes(SAList, SAApi.GetAllScopeAssignments(activeProject.ProjectID),3,3000,"ScopeAssignmentsList");
RetryNTimes(ActList, ActApi.GetAllActivities(activeProject.ProjectID),3,3000,"ActivityList");
...

private bool RetryNTimes(T object, Func<T> func, int times, int WaitInterval, string etext){
    do
    {
        try
        {
            object = func();
        }
        catch (ApiException e)
        {
            if (e.ErrorCode == 401)
            {
                retries++;
                Log.Warning("Unauthorized error while fetching {APIErrorSubject}, try {retries}",eText,retries);
                System.Threading.Thread.Sleep(RetryPause * retries);//Waits 3 and then 6 seconds before retrying.
            }
            else throw;
        }
    } while (object == null || retries < maxRetries);
    if (retries == maxRetries)
    {
        Log.Error("An error has occured while trying to retrieve {APIErrorSubject}, skipped document",eText);
        errorCount++;
        return false;
    }
    return true;
}

I've also read through typedef and function pointers but I'm not sure if it's possible to do with variable types. Any Ideas?

Upvotes: 0

Views: 57

Answers (2)

MatthiasVC
MatthiasVC

Reputation: 3

Based on the idea of asawyer and by looking through some other examples of delegates I've been able to make it work.

static T2 TryNTimes<T1,T2>(Func<T1,T2> func,T1 obj, int times, int WaitInterval)
{
    while (times > 0)
    {
        try
        {
            T2 result = func.Invoke(obj);
            return result;
        }
        catch (Exception e)
        {
            if (--times <= 0)
                throw;
            System.Threading.Thread.Sleep(WaitInterval * times);
        }

    }
    return default;
}

Now I need only 2 steps in my main function

activeWorkspace = TryNTimes(WrkApi.WorkspaceCodeWorkspaceCodeFindByName17, ServiceSettings.sqlConnection.Workspace, 3, 3000)[0];
ProjectList = TryNTimes(WrkApi.GetProjectsByWorkspaceCode, activeWorkspace.code, 3, 3000);

The first one can still generate an error as the default List is empty and you can't take 0th element then. But I guess I can find another way around that issue.

Upvotes: 0

Elbowz
Elbowz

Reputation: 76

That article refers to C language. In C# you can use delegates. Here's a link to start you off.

Upvotes: 1

Related Questions