5
\$\begingroup\$

I'm working on a client proxy for my WebAPI. I've looked at WebApiProxy but I feel DTOs are unnecessary in my scenario.

I made an ApiProxyBase class that supports basic Get, Post, Put and Delete functionality using generics. Using this base class I've setup an implementation as follows:

public sealed class MyProxy : ApiProxyBase
{
    private static readonly string ConnectionString = "MyServiceUrl";
    private static readonly MyProxy Instance = new MyProxy(InitializeConnection());

    private MyProxy(string url) : base(url)
    {

    }

    private static string InitializeConnection()
    {
        var conn = ConfigurationManager.ConnectionStrings[ConnectionString];
        if (conn == null) throw new InvalidOperationException("MyProxy requires a connection string with the name '" + ConnectionString + "'");
        return conn.ConnectionString;
    }

    public static class Users
    {
        public static List<User> List()
        {
            return Instance.Get<List<User>>("users/list");
        }

        public static User Single(int userId)
        {
            return Instance.Get<User>("users/" + userId.ToString());
        }

        public static User Add(User user)
        {
            return Instance.Post("users/add", user);
        }

        public static User Update(User user)
        {
            return Instance.Put("users/update", user);
        }

        public static bool Delete(int userId)
        {
            return Instance.Delete("users/delete/" + userId.ToString());
        }
    }
}

I've read that public nested classes such as this are considered bad practice. To me it feels much cleaner and more readable than implementing each method directly in the proxy like this:

public static List<User> ListUsers()
{
    return Instance.Get<List<User>>("users/list");
}

I plan to add more nested classes for each of the datatypes I need, so the semantics of MyProxy.[Type].Add, MyProxy.[Type].Update...etc. feels very smooth when compared to MyProxy.Add[Type], MyProxy.Update[Type].

Are there any good reasons not to go with this approach?

\$\endgroup\$
  • \$\begingroup\$ Could you give some background as to why you're doing this? What problem does this solve? \$\endgroup\$ – Jeroen Vannevel May 28 '15 at 22:29
  • \$\begingroup\$ Ultimately I need a client proxy for my WebApi so my apps/services can consume it. The code above is what I consider to be a clean and simple approach to solving that. \$\endgroup\$ – Chad May 29 '15 at 18:28
2
\$\begingroup\$

The drawback to this is that you couple two classes together based on an arbitrary property of the outer class named Instance. Also, if you need to write tests around this you will run into issues. I would either make a singleton class for your proxy or instantiate the proxy at application start and make it a property of the application. You'll get the same benefits as your current approach.

If you feel intermediary DTOs are unnecessary, then you have a choice on how the objects you do work with get created which defines how you will deal with breaking changes:

  • If you go with the implementation you're using and everything is written manually by you, when something changes, you fix it by going in and write new objects/props.
  • If you use the client generator that you linked, you still have the option of referencing it directly and not making a middle layer. Then when something changes, you go in, regenerate your client, and fix any compile-time errors.

I think the latter sounds easier to me.

\$\endgroup\$
  • \$\begingroup\$ Using a code generator is not that fun when it generates incompatible code. Then you have to manually hunt down all the compiler errors and fix them. That's easy, but boring, when there's a one-to-one mismatch, like a rename. Not so fun when there are more complex changes. \$\endgroup\$ – Thomas Eyde Oct 5 '15 at 12:57
  • \$\begingroup\$ @ThomasEyde Coming back to this, I realized you could fix both the dependency issues and your concerns about the design by inverting the dependencies. Make your Users an instance class that takes the MyProxy instance in the constructor, and then delegate your calls to the proxy. Wire the injection up using a container. Now you can mock/stub out your proxy object and behavior and isolate it in testing, you have no access modifier concerns, and you have the added benefit of being able to mock out your Users object to test consuming code since it's no longer static. Hey, you have a repository! \$\endgroup\$ – moarboilerplate Oct 27 '15 at 16:17

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.