Create a Web Api that calls another Web Api

Asked

Viewed 1,616 times

1

I created a Web Api here in my work to be consumed by my project Xamarin Forms. It’s working 100% and no problems... Then I was informed that actually here we use 2 web api s for security. That is, I will have to create a Web Api ("frontend") with external access, which would act as a doorman, passing the calls to another Web Api ("backend") and this, only this, has access to the BD and only accepts internally. Since I’m a beginner and I took a beating to be able to build this Web Api and it works, I would like a help in how to do this. I would have to call Webapi 1 and it will carry the values typed by the user up to Web Api 2... this in turn will have the database calls and all the controllers...after the query is that I did not understand what to do, because the data is spit in Json and much of it I was able to make work in Rra by searching.

My code in Xamarin:

ApiCall apiCall = new ApiCall();

                apiCall.GetResponse<List<Envolvido>>("nomes", "Envolvidos", nomepesquisa, nomemae, nomepai, dtnasc, nrg, ncpf).ContinueWith(t =>
               {
                   //Aqui verificamos se houve problema ne requisição
                   if (t.IsFaulted)
                   {
                       Debug.WriteLine(t.Exception.Message);
                       Device.BeginInvokeOnMainThread(() =>
                       {
                           DisplayAlert("Falha", "Ocorreu um erro na Requisição :(", "Ok");
                           //IsBusy = false;
                       });
                   }
                   //Aqui verificamos se a requisição foi cancelada por algum Motivo
                   else if (t.IsCanceled)
                   {
                       Debug.WriteLine("Requisição cancelada");

                       Device.BeginInvokeOnMainThread(() =>
                       {
                           DisplayAlert("Cancela", "Requisição Cancelada :O", "Ok");
                           //IsBusy = false;

                       });
                   }

                   //Caso a requisição ocorra sem problemas, cairemos aqui
                   else
                   {
                       //Se Chegarmos aqui, está tudo ok, agora itemos tratar nossa Lista
                       //Aqui Usaremos a Thread Principal, ou seja, a que possui as references da UI
                       Device.BeginInvokeOnMainThread(() =>
                          {
                              //IsBusy = false;
                              ListaDados.ItemsSource = t.Result;
                              var count = ListaDados.ItemsSource.OfType<object>().Count();
                              if (count == 0)
                              {
                                  DisplayAlert("Cancela", "Não há dados retornados.", "Ok");
                              }
                              else
                                  Navigation.PushAsync(new ResultadosBuscados(ListaDados.ItemsSource));
                          });

                   }

part of my Apicall that calls the Web Api:

public class ApiCall
    {
        static readonly string ApiUrl = "http://Localhost:1762/api/{0}/{1}?nomePesquisa={2}&nomeMae={3}&nomePai={4}&dtNasc={5}&nrg={6}&ncpf={7}";

            public async Task<T> GetResponse<T>(string controller, string method, string nomepesquisa, 
            string nomemae, string nomepai, string dtnasc, string nrg, string ncpf) where T : class
        {
            var client = new System.Net.Http.HttpClient();


            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));


            var urllink = string.Format(ApiUrl, controller, method, nomepesquisa, nomemae, nomepai, dtnasc, nrg, ncpf);
            var response = await client.GetAsync(urllink);

            //Lê a string retornada
            var JsonResult = response.Content.ReadAsStringAsync().Result;

            if (typeof(T) == typeof(string))
                return null;

            //Converte o resultado Json para uma Classe utilizando as Libs do Newtonsoft.Json
            var rootobject = JsonConvert.DeserializeObject<T>(JsonResult);
            return rootobject;
        }
}

My controller code in the Web Api:

[RoutePrefix("api/nomes")]
    public class NomesController : ApiController
    {
        public string GetConnectionString()
        {
            string MeuConnString = "Data Source=(DESCRIPTION ="
                + "(ADDRESS=(PROTOCOL = TCP)(HOST = xxx)(PORT = xxx))"
                + "(CONNECT_DATA = (SERVER = DEDICATED)(service_name = xxx)));"
                + "User Id = xxx; Password=xxx";
            return MeuConnString;
        }


        [HttpGet]
        [Route("Envolvidos")]
        public IEnumerable<Envolvido> GetEnvolv(string nomePesquisa, string nomeMae, string nomePai, string dtnasc
            , string nRG, string nCPF)
        {

            DataSet lretorno = new DataSet();

            string connectionString = GetConnectionString();
            using (OracleConnection connection = new OracleConnection())
            {
                connection.ConnectionString = connectionString;

                OracleDataReader reader = null;
                OracleCommand cmd = new OracleCommand();
                cmd.Connection = connection;
                cmd = new OracleCommand("MOBILE.XAPIMAND.BUSCAPOSCANDIDOSPF", connection);
                cmd.CommandType = CommandType.StoredProcedure;

                //variáveis entrada            
                cmd.Parameters.Add(new OracleParameter("ivnome",nomePesquisa));
                cmd.Parameters.Add(new OracleParameter("ivmae", nomeMae));
                cmd.Parameters.Add(new OracleParameter("ivpai", nomePai));
                cmd.Parameters.Add(new OracleParameter("ivdatanasc", dtnasc));
                cmd.Parameters.Add(new OracleParameter("ivrg", nRG));
                cmd.Parameters.Add(new OracleParameter("icpf", nCPF));
                //variáveis de saida          
                cmd.Parameters.Add(new OracleParameter("oretorno", OracleDbType.RefCursor)).Direction = ParameterDirection.Output;
                cmd.Parameters.Add(new OracleParameter("qretorno", OracleDbType.RefCursor)).Direction = ParameterDirection.Output;

                connection.Open();
                cmd.ExecuteNonQuery();

                reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);

                //CRIO A LISTA
                lretorno.Load(reader, LoadOption.OverwriteChanges, "BUSCAPOSSIVEISCANDIDATOSPF");
                connection.Close();
                connection.Dispose();


                //CARREGO O DATASET E TRANSFORMO PARA IENUMERABLE E RETORNO SEUS VALORES PRO JSON
                return lretorno.Tables[0].AsEnumerable().Select(row => new Envolvido
                {
                    SUSPID = Convert.ToInt32(row["SUSPID"]),
                    IVNOME = Convert.ToString(row["SUSPNOME"]),
                    IVMAE = Convert.ToString(row["SUSPMAE"]),
                    IVPAI = Convert.ToString(row["SUSPPAI"]),
                    IVDATANASC = Convert.ToString(row["SUSPDATANASC"]).Replace(" 00:00:00", ""),
                    IVRG = Convert.ToString(row["RG"]),
                    ICPF = Convert.ToString(row["CPF"]),
                    MANDADO = Convert.ToInt16(row["TEMMANDADO"]),
                    OCORRENCIA = Convert.ToInt16(row["TEMOCORRENCIA"]),

                });


            }
        }

    }
  • What’s the extra security in having two Apis?

  • @jbueno the 1st Web Api ("front") is connected externally... this connects to the 2nd ("back"), which is connected only internally...ie, if a person tries to access the BD from outside the network, theoretically, can not access.

  • 1

    @jbueno and Marcelo, I have serious doubts about this security model, even because the simple fact of making a request to the database should not expose the database. now let’s say Webapi 1 has a serious security problem that allows a hack to take control of the server, in this case it will be within your network and will have access to Webapi 2. And finally, there are situations that is valid to have two services, but the second service would normally WCF and possibly have a nettcp Binding and a more restrictive authentication system.

  • @Tobymosque I agree in parts.... here in my work this is the structure for everything! This Mobile is the first and test, but I was asked to follow the architecture when I did. But as I’m a beginner, it’s difficult. In my Apicall I have the URL call using System.Net.Http.Httpclient() and then enter the controller... that is, now in this "intercom" Web Api I will have to have another URL call for 2nd Web Api and in addition, pass the parameters, returning the dataset of the 2nd Web Api... Confusion in my head. I wanted someone to give an example as it would be, using this my Code.

  • 1

    @Marcelocfernandes in this case you should not have two Webapi, you should have a WCF service using Netpeertcpbinding with point-to-point security, just remember to configure the messages using MTOM encoding.

  • @Marcelocfernandes What is your doubt, really?

  • @Randrade My question is about what to use. I created the Web Api to consume the Oracle BD data and it’s working. Then I was informed that here I could not actually use this architecture. That they use one server for external access and another that only receives internal access and these communicate. My question is how to do this communication...I thought of 2 Web Api s, but I’m beginner and I don’t have much knowledge. A lot of what you talked about here, I don’t have a clue what rsrs are.

Show 2 more comments

1 answer

2

First, two WebAPIs is no safer than just one, this approach will not protect your system from an attack such as MITM, Sql Injection or whatever other attack you might imagine.

If your fear is that an eventual serious failure gives control of the server with the WebAPI 1 is some hacker, in which case he will have full access to the machine and its network, so he could access its entire structure.

Now let’s get to the other problem, Session, all accesses on Monday WebAPI will be performed by the same user, so you will not have a Session per user and will need to use a workaround (that will possibly involve using the Cache and add the SessionID as a Header in all requisitions).

We still have a second problem a little more serious, Authentication and Authorization, as to your second WebAPI will know if the user who made the first request WebAPI have access. In short you will not be able to use the ASP.NET Identity and will have to implement its own.

Another problem involves transactions, say a request from WebAPI 1 need to make two separate calls to WebAPI 2, how will you make a rollback of the first one if the second one goes wrong? a TransactionScope you need it right?

But still, a multi-layered system still has its purpose, I might want to make a presentation layer using AngularJS + WebAPI, and other systems that need to consume this service and some of them cannot make a request http.

In this case you will need a WCF service that offers one or more bindingwhich are appropriate for applications consuming the same. the binding which offers more security for communication between two applications made in .NET is NetPeerTcpBinding... here follows an example.: Peer-to-Peer Programming with WCF and . NET Framework 3.5.

Remembering that a service in WCF allows you to pass a transaction to it, so you can create a TransactionScope in WebAPI, make n calls to serviço and make a rollback safely if necessary.

And to consume a WCF service, just add a Service Reference, the Visual Studio will take all the trouble to create the classes of proxy, control channel opening, messaging, etc...

Now you can ask me why not use the webHttpBinding in the WCF and use a WebAPI as an interface to the Web? the first point is competition, the Async WebAPI can manage a scenario with multiple connections much better, the other point is how the configuration options, you will have a wider range with the WebAPI.

  • I liked the answer, although I did not understand the question. xD

  • 2

    Just one thing. Theoretically, you can use Identity with this template yes, but you’ll have a bigger job of having to pass the user to the second API manually.

  • 1

    @Randrade true, but I still think it’s an additional complexity that brings no real gain.

  • I fully agree. I only commented because in your answer you said you had to develop your own form. This way gives the impression that it is not possible to use, and not that it is not feasible.

  • @Tobymosque Here there is no danger of Transactionscope ... The service Ference is an option. My problem is being lay and beginner in the subject. The infrastructure here is not geared to Mobile. I’m wondering what to use to deepen.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.