0

The first call that takes place in my application is a Login() request to the web service that returns a session ID that will be used for all future calls. However, after enough time, the Session ID may become invalid. So, my call looks like this:

UserService.Status request = serviceInstance.doSomething(id, out result)
// If the error is for an invalid sessionID, log in again
if (request.ErrorCode == 1) { login(); }

Which works fine, but the page will still load without any of the details from the Web Service until a refresh is performed. The simple solution here is to paste serviceInstance.doSomething() into the conditional, but given there are 50+ Web Service methods, it would mean duplicating the same code 50+ times. Is there a clever way of getting around this and re-executing a request for any UserService.Status.Errorcode == 1 situation that arises?

In case it's relevant, the Status object looks something like:

<s:complexType name="Status">
    <s:attribute name="Status" type="tns:ReMAEStatusType" use="required" />
    <s:attribute name="Source" type="s:string" />
    <s:attribute name="Message" type="s:string" />
    <s:attribute name="StackTrace" type="s:string" />
    <s:attribute name="ErrorCode" type="s:int" />
</s:complexType>
Jtaylorapps
  • 5,680
  • 8
  • 40
  • 56
  • You can try implementing a retry logic . https://msdn.microsoft.com/en-us/library/dn589788.aspx – Aravind Jul 26 '16 at 17:46
  • If you check out the last paragraph, that's exactly what I was thinking! I'm impressed I missed this design pattern entirely. The only problem is I'd have to repeat the code for every Request. If I can just figure a way of generalizing the retry pattern for every possible request... perhaps it's time to put the functional programming side of C# to use. – Jtaylorapps Jul 26 '16 at 17:58
  • oh ok. did not notice the edit. having retry block for every method with external service or resource call is a good idea. I don't think it is repeated code. in fact it is a best practice when dealing with cloud resources like azure storage. try something like this http://stackoverflow.com/questions/1563191/cleanest-way-to-write-retry-logic there are some nuget packages with such readymade implementation like https://www.nuget.org/packages/Endjin.Retry/ or you can explore having it as method level attribute based. not sure if it has been tried . – Aravind Jul 26 '16 at 18:09
  • I was able to get the logic figured out thanks to your Retry suggestion, and I combined that with some reflection to decrease about 300 lines of code into a couple dozen. Still deciding if the absurd DRYness and flexibility that reflection provides is worth a potential performance hit. – Jtaylorapps Jul 27 '16 at 14:51
  • Cool. Glad it helped. – Aravind Jul 27 '16 at 18:07

1 Answers1

0

I ended up going with a retry logic combined with reflection. The idea here is to be able to handle a single error for every WebService method without repeating the try-catch loop in every single call.

// Make up to two attempts at the Try block
for (int i = 0; i < 2; i++)
{
    try
    {
        // Invoke some web service method that returns error codes but not exceptions here... I used reflection
        Service.Status request = (Service.Status)typeof(WebService).GetMethod(someString).Invoke(someWebServiceInstance, someArgs);

        if (request.ErrorCode == 0)
        {
            // No errors! Do some stuff. Return a value. Make sure to get out of the loop
            return request.Message;
        }
        else
        {
            // Log some stuff if there was an error...
            Debug.WriteLine("Error Code: " + request.ErrorCode + "\nMessage: " + request.Message);

            // Start handling individual error codes as needed
            if (request.ErrorCode == 1)
            {
                // Seems the session ID is invalid!
                throw new UnauthorizedAccessException(request.Message);
            }
            else
            {
                // Throw some other exceptions....
                // If they can't be handled, make sure to break the loop in the catch block
            }
        }
    }
    catch (UnauthorizedAccessException)
    {
        // Start catching our exceptions. Lets get a new Session ID, and since we didn't return anything
        // The loop will let us give the try block another shot
        login();
    }
Jtaylorapps
  • 5,680
  • 8
  • 40
  • 56