2
\$\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?

asked Dec 31, 2013 at 16:54
\$\endgroup\$
4
  • \$\begingroup\$ Why are you parsing and creating the JSONs instead of using serialization? I think that would simplify your code quite a lot. \$\endgroup\$ Commented Jan 1, 2014 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\$ Commented Jan 2, 2014 at 7:22
  • \$\begingroup\$ Why would that affect the clients? You could still serialize to the same JSON. \$\endgroup\$ Commented Jan 2, 2014 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\$ Commented Jan 2, 2014 at 22:03

1 Answer 1

4
\$\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.

answered Jan 1, 2014 at 6:27
\$\endgroup\$
2
  • \$\begingroup\$ Thanks, this is perfect. I hadn't thought of doing an anonymous function to pass to ProcessServiceCall. \$\endgroup\$ Commented Jan 6, 2014 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\$ Commented Sep 25, 2014 at 8:28

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.