locked
Architecture Question Web Forms and Web API RRS feed

  • Question

  • User-1605345584 posted

    Good Morning,

    I'm looking for some guidance.  I began building a solution which was a WCF Service Library, Service Host, and MVC Client.  I created a common Library that contained the contracts that both the client and service could use in serializing/deserializing objects.  It works well, but I'm not a fan of giant controllers that I've gotten with this approach.

    I'm now looking to change it to WEB API and Web Forms.  .NET Core is currently not an option. 

    I can build a solution that is a Web Application and add a controller and both the application and api can leverage the same classes and contracts.  

    This raises some questions.  I'm not sure if this is a better approach.

    1. My app is currently intranet based, but the functionality will ultimately be used in an internet setting.   That's why I wanted to a) separate the operations from the pages and b) why I wanted to expose them.
    2. My web forms application is supposed to work, in essence, separately while sharing the code.  I want the web forms to submit requests to the API, after creating the necessary custom headers.  The custom hears contain information like API Key, calling IP Address (we control access by IP), etc..  So, I cannot create those in the controller because that is where I would be deciphering the header, I believe....????  This is where I'm confused.  In an MVC app, the controller is with the calling application and the service is somewhere else.  

    Question...

    Do create a page, then post back to my page, create the client, add the headers and then call the API?  Is that where I'm tripping up on this?  Personally, I'm not even sure there is an advantage of one over the other.

    Thanks,

    - N

    Tuesday, May 12, 2020 2:10 PM

All replies

  • User1120430333 posted

    You use HTTPClient to call an action method in a controller in a WebAPI.

    https://www.c-sharpcorner.com/article/calling-web-api-using-httpclient/

    Your Webforms should be calling a Service layer a classlib project.

    Example code calling methods on WebAPI for CRUD operations  with database sitting behind the WebAPI. 

    sing System;
    using System.Collections.Generic;
    using System.Net.Http;
    using System.Net.Http.Headers;
    using System.Text;
    using Entities;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    
    namespace ServiceLayer
    {
        public class ArticleSvc :IArticleSvc
        {
            public List<DtoArticle> GetAll()
            {
                var dtoarticles = new List<DtoArticle>();
    
                using (var client = new HttpClient())
                {
                    var uri = new Uri("http://localhost/WebAPI/api/article/GetAll");
    
                    var response = client.GetAsync(uri).Result;
    
                    if (!response.IsSuccessStatusCode)
                        throw new Exception(response.ToString());
    
                    var responseContent = response.Content;
                    var responseString = responseContent.ReadAsStringAsync().Result;
    
                    dynamic articles = JArray.Parse(responseString) as JArray;
    
                    foreach (var obj in articles)
                    {
                        DtoArticle dto = obj.ToObject<DtoArticle>();
    
                        dtoarticles.Add(dto);
                    }
                }
    
                return dtoarticles;
            }
    
            public List<DtoArticle> GetArticlesByAuthorId(int id)
            {
                var dtoarticles = new List<DtoArticle>();
    
                using (var client = new HttpClient())
                {
                    var uri = new Uri("http://localhost/WebAPI/api/article/GetArticlesByAuthorId?id=" + id);
    
                    var response = client.GetAsync(uri).Result;
    
                    if (!response.IsSuccessStatusCode)
                        throw new Exception(response.ToString());
    
                    var responseContent = response.Content;
                    var responseString = responseContent.ReadAsStringAsync().Result;
    
                    dynamic articles = JArray.Parse(responseString) as JArray;
    
                    foreach (var obj in articles)
                    {
                        DtoArticle dto = obj.ToObject<DtoArticle>();
    
                        dtoarticles.Add(dto);
                    }
                }
    
                return dtoarticles;
            }
            public DtoArticle Find(int id)
            {
                DtoArticle dto;
    
                using (var client = new HttpClient())
                {
                    var uri = new Uri("http://localhost/WebAPI/api/article/Find?id=" + id);
                    HttpResponseMessage getResponseMessage = client.GetAsync(uri).Result;
    
                    if (!getResponseMessage.IsSuccessStatusCode)
                        throw new Exception(getResponseMessage.ToString());
    
                    var responsemessage = getResponseMessage.Content.ReadAsStringAsync().Result;
    
                    dynamic article = JsonConvert.DeserializeObject(responsemessage);
    
                    dto = article.ToObject<DtoArticle>();
                }
    
                return dto;
            }
    
            public void Add(DtoArticle dto)
            {
                using (var client = new HttpClient { BaseAddress = new Uri("http://localhost") })
                {
                    string serailizeddto = JsonConvert.SerializeObject(dto);
    
                    var inputMessage = new HttpRequestMessage
                    {
                        Content = new StringContent(serailizeddto, Encoding.UTF8, "application/json")
                    };
    
                    inputMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    
                    HttpResponseMessage message =
                        client.PostAsync("WebAPI/api/article/Add", inputMessage.Content).Result;
    
                    if (!message.IsSuccessStatusCode)
                        throw new Exception(message.ToString());
                }
            }
    
            public void Update(DtoArticle dto)
            {
                using (var client = new HttpClient { BaseAddress = new Uri("http://localhost") })
                {
                    string serailizeddto = JsonConvert.SerializeObject(dto);
    
                    var inputMessage = new HttpRequestMessage
                    {
                        Content = new StringContent(serailizeddto, Encoding.UTF8, "application/json")
                    };
    
                    inputMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    
                    HttpResponseMessage message =
                        client.PostAsync("WebAPI/api/article/Update", inputMessage.Content).Result;
    
                    if (!message.IsSuccessStatusCode)
                        throw new Exception(message.ToString());
                }
            }
    
            public void Delete(DtoId dto)
            {
                using (var client = new HttpClient { BaseAddress = new Uri("http://localhost") })
                {
                    string serailizeddto = JsonConvert.SerializeObject(dto);
    
                    var inputMessage = new HttpRequestMessage
                    {
                        Content = new StringContent(serailizeddto, Encoding.UTF8, "application/json")
                    };
    
                    inputMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    
                    HttpResponseMessage message =
                        client.PostAsync("WebAPI/api/article/Delete", inputMessage.Content).Result;
    
                    if (!message.IsSuccessStatusCode)
                        throw new Exception(message.ToString());
                }
            }
        }
    }
    

    Tuesday, May 12, 2020 2:55 PM
  • User475983607 posted

    Do create a page, then post back to my page, create the client, add the headers and then call the API?

    Sure.

    Personally, I'm not even sure there is an advantage of one over the other.

    The difference between WCF and Web API is WCF can handle more protocols while Web API has one; HTTP.  If you only need HTTP then I recommend Web API.  

    What is your intention?  Share your services with other clients?  If so, a physical service tier is a good approach.  It is easier to manage security and scale out. 

    Tuesday, May 12, 2020 3:01 PM
  • User753101303 posted

    Hi,

    I'm not sure to see which question you are asking.

    For WCF vs Web API you can also have a look at https://docs.microsoft.com/en-us/dotnet/framework/wcf/wcf-and-aspnet-web-api the idea being to use Web API unless you really need some WCF particular feature which doesn't seems to be the case.

    If you want to share code between the client and the server it could go in its own DLL.

    This is where I'm confused.  In an MVC app, the controller is with the calling application and the service is somewhere else.

    But the web api side include controllers as well (the controller just respond to an http, request). Try perhaps https://www.tutorialsteacher.com/webapi/web-api-controller or https://docs.microsoft.com/en-us/aspnet/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api to better see how the this "Web API" featyure works.

    Tuesday, May 12, 2020 4:36 PM
  • User-1605345584 posted

    Thanks for the reply.  Your point about the service "layer" is spot on.  In reality we are talking about a separation between the client/request and service/response.  In a single project, which is how I have mine implemented, the separation is not as clear, but essentially is the pages that a user would access in a web forms app, including the postback or ajax calls and then the API (available through routes).

    In my situation, I do require a custom header to be present in the client request - so AJAX calls will need to route to a handler that creates and instance of the HttpClient (with custom header) and the appropriate API URI.

    I wasn't sure whether to move from the WCF solution that I had, but it just had too many parts.  I'm not 100% sure yet, but think I'm going to like my current approach now that I've determined where to logically split the client from service within the same project.

    Thanks,

    - N

    Tuesday, May 12, 2020 7:49 PM
  • User1120430333 posted

    Yes Seperation of Concerns is always a good approach to take.

    https://en.wikipedia.org/wiki/Separation_of_concerns

    You should also look into using the DTO pattern and using a classlib project to hold them referenced by all projects that need to know about the DTO(s). 

    https://docs.microsoft.com/en-us/aspnet/web-api/overview/data/using-web-api-with-entity-framework/part-5

    https://www.codeproject.com/articles/1050468/data-transfer-object-design-pattern-in-csharp

    Wednesday, May 13, 2020 5:48 AM