0

I am working on an MVC 5 web application. I have the following layers:-

  1. Views
  2. Controller classes.
  3. Repository classes, which are being referenced inside the controller classes.
  4. Model classed
  5. Entity framework DB context.

now i have the following requirement:-

Inside some action methods I want my application to be sending some API calls (using WebClient()) to 3rd party application.

Where the API calls will almost be the same for all the action methods, except for the Description parameter. Now I can have this shared logic inside my repository class, and reference it from my action methods. But as I know that repository class should not expose or reference WebClient() or similar web classes, as repository should deals with databases and model classes only. So I am not sure what is the best place to manage shared WebClient calls ? so from the action method I only call the shared class and pass the description field ?

For example here is a sample of an action method which directly contain the web client :-

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Server s)
{
    if (ModelState.IsValid)
    {
        try
        {
            //code goes here....

            XmlDocument doc = new XmlDocument();
            using (var client = new WebClient())
            {
                var query = HttpUtility.ParseQueryString(string.Empty);
                query["username"] = System.Web.Configuration.WebConfigurationManager.AppSettings["ApiUserName"];
                query["password"] = System.Web.Configuration.WebConfigurationManager.AppSettings["ApiPassword"];
                query["assetType"] = controllername;
                query["operation"] = "UpdateAsset";
                query["assetName"] = s.RESOURCENAME;
                query["description"] = s.DESCRIPTION;
                //code goes here
                var url = new UriBuilder(apiurl);
                url.Query = query.ToString();
                try
                {
                    string xml = client.DownloadString(url.ToString());
                    doc.LoadXml(xml);
                    updatestatus = doc.SelectSingleNode("/operation/operationstatus").InnerText;
                }
                catch (WebException ex)
                {
                    ModelState.AddModelError(string.Empty, "Error occurred:" + ex.InnerException.Message);
                }
            }
        }
    }
}

now i do not want to be adding the same WebClient method on multiple action methods,, but rather to have the WebClient() on a shared class, and reference it from the related action methods .

amatellanes
  • 3,645
  • 2
  • 17
  • 19
John John
  • 1
  • 72
  • 238
  • 501
  • 1
    Can you please show us a snippet of your code? So we can see how it fits together? – Jamie Rees Feb 29 '16 at 13:02
  • @JamieR can you check my edit ,, i provided a sample of an action method,, which directly contain the WebClient what i am trying to do is to move this shared WebClient to a shared place.. – John John Feb 29 '16 at 13:14

2 Answers2

1

Code sample will help, but overall I think you're on the right track here.

but as i know that repository class should not expose or reference WebClient() or similar web classes, as repository should deals with databases and model classes only

It's not just about databases. My feeling is repositories deal with "data-sources" and external services fall under this. There are no absolute rules about this. What makes sense in your situation?

So I am not sure what is the best place to manage shared WebClient calls ?

I think the repository is fine. Based on your architecture, where else would it fit? You can always add a WebApi piece, but it may not add any value and just serve to complicate things.

so from the action method I only call the shared class and pass the description field ?

Looks like a plan to me. You can also skip the controller/action methods calls and go to the services straight from you views via ajax calls

Big Daddy
  • 5,160
  • 5
  • 46
  • 76
  • i editted my question with sample code,, where i am showing the long approach to have the WebClient() class directly inside each action method,,, – John John Feb 29 '16 at 13:16
  • 1
    @johnG...The code is as I expected and of course you don't want to repeat it. Creating a repo to handle this is fine or a javascript solution. – Big Daddy Feb 29 '16 at 13:20
  • but i was against having http related features inside the repo ,, maybe i can create a separate repo to handle http ,, not sure.. – John John Feb 29 '16 at 13:37
  • 1
    @johnG...the repo should be a C# class/method that takes parameters. The only http issues that arise should be from your WebClient implementation and these will probably happen regardless of where the code lives. If you are having http issues outside of your WebClient code, then you've got other problems. – Big Daddy Feb 29 '16 at 13:49
  • no i am not saying i am facing a real problems (bugs) i am talking about architecture point of view... since repository should handle data and interact with model classes,, and it should not handle http requests which is a more Controller classes responsibility.. – John John Feb 29 '16 at 14:00
  • 1
    @johnG...I create classes when I don't have a 'pure' repository need in my mvc layer. I name them like this: PersonController >> PersonControllerService and keep them in a ControllerServices namespace. – Big Daddy Feb 29 '16 at 14:29
  • so are you saying that i can create a separate service classes as shown here http://www.asp.net/mvc/overview/older-versions-1/models-data/validating-with-a-service-layer-cs ? also seems i can have these classes as helper classes as mentioned here http://stackoverflow.com/questions/11515973/where-can-i-put-custom-classes-in-asp-net-mvc .. not sure which approach to follow and why ? – John John Feb 29 '16 at 15:12
  • 1
    @johnG...the second link seems more appropriate for you. Why? It gives you the SOC that you're seeking. I do this a lot. – Big Daddy Feb 29 '16 at 15:38
  • can you advice more on this if possible,, why helper classes will be more suitable to use in my case compared to service classes ? – John John Feb 29 '16 at 15:50
  • 1
    @johnG...I call then "service" classes, some people call the "helper" or "repository" classes. I just comes down to your preference. The key here is the SOC. – Big Daddy Feb 29 '16 at 16:16
  • but looking deeper at each approach seems they are being referenced and used differently ,, is this correct ? the helper classes are being reference inside the Controller classes using the "using" statement , while service classes are being referenced in the same way i reference my current repository class ..such as "private repo = new Repository();"... – John John Feb 29 '16 at 16:19
1

You can create an Action Filter to manage this API call... so you don't need to polute your action with this code o calls to other classes.

If the description is somehow static in each action, you can even put the description in the decorator itself.

[Httppost]
[ValidateAntiForgeryToken]
[MyApiFilter(Description="theDescription")]
public ActionResult Create(Server s)
{
    //Your action code
}

If you can't place the description in the decorator and need something more dynamic, you can set some parameter inside the action code, to be taken by the filter at runtime.

[Httppost]
[ValidateAntiForgeryToken]
[MyApiFilter]
public ActionResult Create(Server s)
{
    //Your action code

    this.SetAdditionalInfo(myDescription)
}

In your BaseController:

public void SetAdditionalInfo(string description)
{
    this.APICallDescription = description;
}

The base ActionFilterAttribute class has the following methods that you can override:

OnActionExecuting – This method is called before a controller action is executed.

OnActionExecuted – This method is called after a controller action is executed.

OnResultExecuting – This method is called before a controller action result is executed.

OnResultExecuted – This method is called after a controller action result is executed.

Romias
  • 13,783
  • 7
  • 56
  • 85
  • but using action filter will always do the API call before calling the action method ,, is this correct ?but in my case i want the API call to be initiated at certain stage inside my action method implementation,, not necessary the first thing to do.. – John John Feb 29 '16 at 13:39
  • 1
    Well, depending the method you use in the Filter, you can trigger the filter before or after the action executes. Check my Update. If you need to call this in different places/order within the actions... it could be better to simply use a helper class call to a method that encapsulates the API call. – Romias Feb 29 '16 at 13:54
  • yes i need to call this in different places/order within the actions. so what do you mean exactly by helper class ? could this be a repository class ? or another controller class ? can you adivce ? – John John Feb 29 '16 at 14:02
  • 1
    I would do another class... I call them "Controller Helper Class"... so I can move complex code to that class and then call this class from the controller. Then you call it like YourControllerHelper.APIMethod( ) passing all the parameters needed. Ideally it could be make that method static. – Romias Feb 29 '16 at 14:06
  • so you mean to have something such as this http://stackoverflow.com/questions/11515973/where-can-i-put-custom-classes-in-asp-net-mvc ?? – John John Feb 29 '16 at 14:28
  • 1
    Yep... that. To avoid the "var helper = new APIHelper()" I suggest to make the method static... so you just call it as "APIHelper.Method()", But the idea is described perfectly in that answer. – Romias Feb 29 '16 at 14:30
  • 1
    Some people call this classes as "Services", instead of Controller Helpers – Romias Feb 29 '16 at 14:32
  • but seems services classes are used mainly for validation ,, as described here http://www.asp.net/mvc/overview/older-versions-1/models-data/validating-with-a-service-layer-cs and is being called differently than using helper classes,, so not sure which best fit in my case? – John John Feb 29 '16 at 14:59
  • 1
    It is just a term.. just use a class to put code in it... the naming is just that. – Romias Feb 29 '16 at 19:38
  • but it is not only the names which differ, seems the helper classes will be referenced using the "using" statement, while service layer is being referenced same as i reference the repository class .. not sure why/when to use each ? – John John Feb 29 '16 at 23:56