4

I am currently working on a website and I had a good separation of concerns following a repository pattern with repositories and managers. Now, I am attempting to implement a Web API as I would greatly benefit from it in the future being able to use it from various clients. Since I am fairly new to REST services, I am having trouble with the correct procedure to consume my web API from a Service in my MVC4 application to then use that service in my MVC controllers. I do not want to have to use knockout for every call to the API.

My Web APIs look something like this(simplified):

public class UserController : ApiController
{
    private readonly IUserManager _manager;

    public UserController(IUserManager manager)
    {
        this._manager = manager;
    }

    // GET api/user
    public IEnumerable<User> Get()
    {
        return _manager.GetAll();
    }

    // GET api/user/5
    public User Get(int id)
    {
        return _manager.GetById(id);
    }

    // POST api/user
    public void Post(User user)
    {
        _manager.Add(user);
    }

    // PUT api/user/5
    public void Put(User user)
    {
        _manager.Update(user);
    }

    // DELETE api/user/5
    public void Delete(User user)
    {
        _manager.Delete(user);
    }
}

I essentially would like to create a service to consume my web API as such:

public class UserService : IUserService
{
    ....Implement something to get,post,put,and delete using the api.
} 

so then I can use it in my mvc controller:

public class UserController: Controller
{
    private readonly IUserService _userService;

    public UserController(IUserService userService)
    {
        this._userService = userService;
    }
    //And then I will be able to communicate with my WebAPI from my MVC controller
}

I know this is possible because I have seen it done at some workplaces but it is very difficult to find articles about this, I have only found articles explaining how to consume web API through knockout. Any help or tips would be greatly appreciated.

2 Answers 2

1

Have a look at the implementation over here: https://github.com/NBusy/NBusy.SDK/blob/master/src/NBusy.Client/Resources/Messages.cs

It basically makes use of HttpClient class to consume Web API. One caveat though, all responses are wrapped in a custom HttpResponse class in that sample. You don't need to do that and can simply use the retrieved DTO object as the return type or a raw HttpResponseMessage class.

Sign up to request clarification or add additional context in comments.

3 Comments

This is just what I was looking for. Well, at least the start to it. Thank you very much. Just one more question that I hope you could answer for me. Do I have to run my API separately for this to work? Or host it? I am at least 80% sure that I should be able to run my entire solution (including MVC4 app and WebApi's) and be able to hit the API correct?
Nope, not at all. I needed to separate the backend from the frontend for that particular project but nothing stops you from having both the API & MVC in the same project.
Okay, I will look through your project some more. So you are saying that by running my solution with the MVC Project as the startup project should be enough to be able to hit the API?
1

You might want to create a static class, I created a separate Class Library to use across solutions that might want to use the API.

NOTE: I use RestSharp for POST and PUT operation since I haven't been able to get them to work using the regular HttpClient over SSL. As you can see documented in this question.

internal static class Container
{
    private static bool isInitialized;
    internal static HttpClient Client { get; set; }
    internal static RestClient RestClient { get; set; }

    /// <summary>
    /// Verifies the initialized.
    /// </summary>
    /// <param name="throwException">if set to <c>true</c> [throw exception].</param>
    /// <returns>
    ///     <c>true</c> if it has been initialized; otherwise, <c>false</c>.
    /// </returns>
    /// <exception cref="System.InvalidOperationException">Service must be initialized first.</exception>
    internal static bool VerifyInitialized(bool throwException = true)
    {
        if (!isInitialized)
        {
            if (throwException)
            {
                throw new InvalidOperationException("Service must be initialized first.");
            }
        }

        return true;
    }

    /// <summary>
    /// Initializes the Service communication, all methods throw a System.InvalidOperationException if it hasn't been initialized.
    /// </summary>
    /// <param name="url">The URL.</param>
    /// <param name="connectionUserName">Name of the connection user.</param>
    /// <param name="connectionPassword">The connection password.</param>
    internal static void Initialize(string url, string connectionUserName, string connectionPassword)
    {
        RestClient = new RestClient(url);
        if (connectionUserName != null && connectionPassword != null)
        {
            HttpClientHandler handler = new HttpClientHandler
            {
                Credentials = new NetworkCredential(connectionUserName, connectionPassword)
            };
            Client = new HttpClient(handler);
            RestClient.Authenticator = new HttpBasicAuthenticator(connectionUserName, connectionPassword);
        }
        else
        {
            Client = new HttpClient();
        }
        Client.BaseAddress = new Uri(url);
        isInitialized = true;
    }
}

public static class UserService
{
    public static void Initialize(string url = "https://serverUrl/", string connectionUserName = null, string connectionPassword = null)
    {
        Container.Initialize(url, connectionUserName, connectionPassword);
    }

    public static async Task<IEnumerable<User>> GetServiceSites()
    {
        // RestSharp example
        Container.VerifyInitialized();
        var request = new RestRequest("api/Users", Method.GET);
        request.RequestFormat = DataFormat.Json;
        var response = await Task.Factory.StartNew(() => { return Container.RestClient.Execute<List<User>>(request); }).ConfigureAwait(false);
        return response.Data;
        // HttpClient example
        var response = await Container.Client.GetAsync("api/Users/").ConfigureAwait(false);
        return await response.Content.ReadAsAsync<IEnumerable<User>>().ConfigureAwait(false);
    }

    public static async Task<User> Get(int id)
    {
        Container.VerifyInitialized();
        var request = new RestRequest("api/Users/" + id, Method.GET);
        var response = await Task.Factory.StartNew(() => { return Container.RestClient.Execute<User>(request); }).ConfigureAwait(false);
        return response.Data;
    }

    public static async Task Put(int id, User user)
    {
        Container.VerifyInitialized();
        var request = new RestRequest("api/Users/" + id, Method.PATCH);
        request.RequestFormat = DataFormat.Json;
        request.AddBody(user);
        var response = await Task.Factory.StartNew(() => { return Container.RestClient.Execute(request); }).ConfigureAwait(false);
    }

    public static async Task Post(User user)
    {
        Container.VerifyInitialized();
        var request = new RestRequest("api/Users", Method.POST);
        request.RequestFormat = DataFormat.Json;
        request.AddBody(user);
        var response = await Task.Factory.StartNew(() => { return Container.RestClient.Execute(request); }).ConfigureAwait(false);
    }

    public static async Task Delete(int id)
    {
        Container.VerifyInitialized();
        var request = new RestRequest("api/Users/" + id, Method.DELETE);
        var response = await Task.Factory.StartNew(() => { return Container.RestClient.Execute(request); }).ConfigureAwait(false);
    }
}

Comments

Your Answer

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.