1
\$\begingroup\$

I'm responsible for maintaining a web service project in c#. I have one service class with a bunch of methods that look a lot like this:

    [OperationContract]
    [WebInvoke(Method = "POST", UriTemplate = "v1/Login", ResponseFormat = WebMessageFormat.Json)]
    public string Login()
    {
        try
        {
            JObject incomingRequestJson = retrieveJson();
            JObject returningJson = new JObject();

            string accountId = incomingRequestJson.SelectToken("accountId", true).ToString();
            string username = incomingRequestJson.SelectToken("userName", true).ToString();
            string password = incomingRequestJson.SelectToken("password", true).ToString();

            LoginResult result = readerBLL.Login(accountId, username, password);
            returningJson.Add(new JProperty("userSessionId", result.userSessionId));
            returningJson.Add(new JProperty("friendlyUserName", result.friendlyUserName));

            return returningJson.ToString(Newtonsoft.Json.Formatting.None);
        }
        catch (Exception ex)
        {
            throw new WebFaultException<string>(ex.Message.ToString(), HttpStatusCode.OK);
        }
    }

Note that retrieveJson() grabs a JSON string from the HttpContext and runs JObject.Parse() on it. Note also that the consumer of this service is a Flex app, so I do need the WebFaultException business with the "OK" response code (The networking component in Flex treats connection timeouts and all HTTP error codes exactly the same - no further data other than

I don't like the way I have the try-catch block repeated in every method, so I tried making the following method:

private object invokeBusinessLogic(Func<JObject, object> f)
    {
        try
        {
            return f(retrieveJson());
        }
        catch (Exception ex)
        {
            WebFaultException<string> wfe = new WebFaultException<string>(ex.Message.ToString(), HttpStatusCode.OK);
            throw wfe;
        }
    }

Then my service methods can look like this:

public object Login()
{
    LoginResult result = (LoginResult) invokeBusinessLogic(readerBLL.Login);
    returningJson.Add(new JProperty("userSessionId", result.userSessionId));
    returningJson.Add(new JProperty("friendlyUserName", result.friendlyUserName));

    return returningJson.ToString(Newtonsoft.Json.Formatting.None);
}

However, this has the problem that the use of JSON to carry the request data gets exposed to the business layer. Is there a better way to avoid the duplicate try-catch blocks than this invokeBusinessLogic idea?

\$\endgroup\$
  • \$\begingroup\$ Why are you parsing and creating the JSONs instead of using serialization? I think that would simplify your code quite a lot. \$\endgroup\$ – svick Jan 1 '14 at 15:41
  • \$\begingroup\$ Historical reasons. I'd love to change it, but then the clients of this service would need to be updated. That's something for version 2 of this service. \$\endgroup\$ – Brian Jan 2 '14 at 7:22
  • \$\begingroup\$ Why would that affect the clients? You could still serialize to the same JSON. \$\endgroup\$ – svick Jan 2 '14 at 11:44
  • \$\begingroup\$ Oh, perhaps I misunderstood you. I thought doing serialization would mean function signatures like public LoginResult Login() in the service layer -- and that would break my clients. The current code actually sends an escaped string rather than a real JSON string :/ \$\endgroup\$ – Brian Jan 2 '14 at 22:03
3
\$\begingroup\$

I'm not sure why your change all of a sudden would expose data to the business layer when it didn't before.

If you have a pattern of methods which look like this:

public string MyServiceCall()
{
    try
    {
        JObject incomingRequestJson = retrieveJson();
        JObject returningJson = new JObject();

        // do stuff

        return returningJson.ToString(Newtonsoft.Json.Formatting.None);
    }
    catch (Exception ex)
    {
        throw new WebFaultException<string>(ex.Message.ToString(), HttpStatusCode.OK);
    }
}

Then you can simply add a helper method to your service implementation:

private string ProcessServiceCall(Func<JObject, JObject> processor)
{
    try
    {
        JObject incomingRequestJson = retrieveJson();
        JObject returningJson = processor(incomingRequestJson);

        return returningJson.ToString(Newtonsoft.Json.Formatting.None);
    }
    catch (Exception ex)
    {
        throw new WebFaultException<string>(ex.Message.ToString(), HttpStatusCode.OK);
    }
}

and your service call then becomes:

public string MyServiceCall()
{
    ProcessServiceCall(incomingRequestJson => {

        string accountId = incomingRequestJson.SelectToken("accountId", true).ToString();
        string username = incomingRequestJson.SelectToken("userName", true).ToString();
        string password = incomingRequestJson.SelectToken("password", true).ToString();

        JObject result = new JObject();

        LoginResult result = readerBLL.Login(accountId, username, password);
        result.Add(new JProperty("userSessionId", result.userSessionId));
        result.Add(new JProperty("friendlyUserName", result.friendlyUserName));

        return result;
    }
}

This should be a simple refactoring on your service class and not expose any more json to the business logic than before.

\$\endgroup\$
  • \$\begingroup\$ Thanks, this is perfect. I hadn't thought of doing an anonymous function to pass to ProcessServiceCall. \$\endgroup\$ – Brian Jan 6 '14 at 21:24
  • \$\begingroup\$ Maybe reuse source code (common logic, implementation) for WebAPI, WCF Service (JSON), WCF Service (SOAP-XML)? IMHO, better samples for minimize learning curve are real applications with full source code and good patterns \$\endgroup\$ – Kiquenet Sep 25 '14 at 8:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.