Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for complex type parameter binding through FromUri #97

Open
wants to merge 50 commits into
base: master
Choose a base branch
from

Conversation

lust4life
Copy link
Contributor

@lust4life lust4life commented Jun 2, 2016

  1. Add support for complex type parameter binding through FromUri

maybe add w=1 (ignore whitespace) can make pr compare more clearly.

Add support for complex type parameter binding through FromUri

if our api controller has this signature:(you can find this in WebApiProxy.Api.Sample => TestController)

using System.Web.Http;
using System.Web.Http.Description;

namespace WebApiProxy.Api.Sample.Controllers
{
    [RoutePrefix("api/test")]
   public class TestController : ApiController
    {
        [HttpGet]
        [ResponseType(typeof(GenericBase<string>))]
        [Route("GetFromSimpleArg")]
        public IHttpActionResult GetFromSimpleArg(string id)
        {
            return Ok(new GenericBase<string>() {Id = id});
        }

        [HttpGet]
        [ResponseType(typeof(ComplexModel))]
        [Route("GetFromComplexArg")]
        public IHttpActionResult GetFromComplexArg([FromUri]ComplexModel dataArg)
        {
            return Ok(dataArg);
        }

        [HttpGet]
        [ResponseType(typeof(NestedModel))]
        [Route("GetFromMixedArg")]
        public IHttpActionResult GetFromMixedArg(int id, [FromUri] ComplexModel dataArg)
        {
            return Ok(new NestedModel()
            {
                Id = id,
                ComplexModel = dataArg
            });
        }


        [HttpPost]
        [Route("PostFromMixedArg")]
        public TotalResult PostFromMixedArg(string simpleStr,[FromUri] NestedModel uriNestedArg,[FromBody] ComplexModel bodyComplexArg)
        {
            /*
                this will not work in proxy client, because uriNestedArg will not generate 
                a uri for client to post,but it can be support in proxyTemplate.tt 
                if nested class[array,list...] is used for uri parameters binding become more common. 

                but this can be request from browser[post uri with body part], it means this Action has no problem.
             */


            return new TotalResult()
            {
                SimpleStr = simpleStr,
                ComplexModel = bodyComplexArg,
                NestedModel = uriNestedArg
            };
        }


        [HttpPost]
        [Route("PostFromMixedArg2")]
        public TotalResult PostFromMixedArg2(string simpleStr, [FromUri]ComplexModel uriComplexArg, [FromBody]NestedModel bodyNestedArg)
        {
            return new TotalResult()
            {
                SimpleStr = simpleStr,
                ComplexModel = uriComplexArg,
                NestedModel = bodyNestedArg
            };
        }


        // PUT api/values/5
        public void Put(int id, [FromBody]string value)
        {
        }



        // DELETE api/values/5
        public void Delete(int id)
        {
        }
    }

    public class GenericBase<T>
    {
        public T Id { get; set; }
    }

    public class ComplexModel
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }

    public class NestedModel:GenericBase<int>
    {
        public ComplexModel ComplexModel { get; set; }
    }

    public class TotalResult
    {
        public string SimpleStr { get; set; }
        public ComplexModel ComplexModel { get; set; }
        public NestedModel NestedModel { get; set; }
    }
}

for those Action use ComplexModel and bind it FromUri, the current will generate code like this:

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dataArg"></param>
        /// <returns></returns>
        protected virtual async Task<HttpResponseMessage> GetFromComplexArgAsyncMsg(ComplexModel dataArg)
        {
            return await HttpClient.GetAsync("api/test/GetFromComplexArg?Name=" + Name + "&Age=" + Age);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dataArg"></param>
        /// <returns></returns>
        public virtual async Task<ComplexModel> GetFromComplexArgAsync(ComplexModel dataArg)
        {
            var result = await HttpClient.GetAsync("api/test/GetFromComplexArg?Name=" + Name + "&Age=" + Age);

            EnsureSuccess(result);

            return await result.Content.ReadAsAsync<ComplexModel>();
        }

the name and age arguments will cause a compile error.

i support it like this :

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dataArg"></param>
        /// <returns></returns>
        public virtual async Task<ComplexModel> GetFromComplexArgAsync(ComplexModel dataArg)
        {
            var requestUrl = "api/test/GetFromComplexArg";


            var queryHasParamUrl = "";



            var queryNoParamUrl = GenerateGetFromComplexArgQueryString(dataArg);


            if (string.IsNullOrEmpty(queryHasParamUrl))
            {
                requestUrl = requestUrl + "?" + queryNoParamUrl;
            }
            else
            {
                requestUrl = requestUrl + "?" + queryHasParamUrl + "&" + queryNoParamUrl;
            }


            var result = await HttpClient.GetAsync(requestUrl );


            EnsureSuccess(result);

            return await result.Content.ReadAsAsync<ComplexModel>();
        }



        protected virtual string GenerateGetFromComplexArgQueryString(ComplexModel dataArg)
        {
            var kvList = GenerateGetFromComplexArgKeyValueList( dataArg );
            var urlTpl = GenerateQueryStrFromKvList(kvList);

            return urlTpl;
        }

        protected virtual List<KeyValuePair<string, object>> GenerateGetFromComplexArgKeyValueList(ComplexModel dataArg)
        {
            // Name={Name}&Age={Age}
            throw new NotImplementedException();
        }

and what we need to do is , find all NotImplementedException method, implement its client and override it ( GenerateGetFromComplexArgKeyValueList ) like this:

      public class ProxyClient:TestClient
        {
            protected override List<KeyValuePair<string, object>> GenerateGetFromComplexArgKeyValueList(ComplexModel dataArg)
            {
                return new List<KeyValuePair<string, object>>()
                {
                    new KeyValuePair<string, object>("Name", dataArg.Name),
                    new KeyValuePair<string, object>("Age", dataArg.Age),
                };
            }
         }

after that , the client can process it correctly, i use a console project test it, here is the result and code .

using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Test.Proxies.Clients;
using Test.Proxies.Models;

namespace ConsoleApplication1
{
    class Program
    {

        public class ProxyClient:TestClient
        {
            protected override List<KeyValuePair<string, object>> GenerateGetFromComplexArgKeyValueList(ComplexModel dataArg)
            {
                return new List<KeyValuePair<string, object>>()
                {
                    new KeyValuePair<string, object>("Name", dataArg.Name),
                    new KeyValuePair<string, object>("Age", dataArg.Age),
                };
            }

            protected override List<KeyValuePair<string, object>> GenerateGetFromMixedArgKeyValueList(int id, ComplexModel dataArg)
            {
                return new List<KeyValuePair<string, object>>()
                {
                    new KeyValuePair<string, object>("Name", dataArg.Name),
                    new KeyValuePair<string, object>("Age", dataArg.Age),
                };
            }

            protected override List<KeyValuePair<string, object>> GeneratePostFromMixedArg2KeyValueList(string simpleStr, ComplexModel uriComplexArg, NestedModel bodyNestedArg)
            {
                return new List<KeyValuePair<string, object>>()
                {
                    new KeyValuePair<string, object>("Name", uriComplexArg.Name),
                    new KeyValuePair<string, object>("Age", uriComplexArg.Age),
                };
            }
        }


        static void Main(string[] args)
        {
            var client = new ProxyClient();
            var v1 = client.GetFromSimpleArg("just say this is my name");
            Console.WriteLine("1---" + JsonConvert.SerializeObject(v1));

            v1 = client.GetFromSimpleArgAsync("just say this is my name").Result;
            Console.WriteLine("1-async---" + JsonConvert.SerializeObject(v1));

            var complexModel = new ComplexModel() {Age = 206, Name = "super star"};
            var v2 = client.GetFromComplexArg(complexModel);
            Console.WriteLine("2---" + JsonConvert.SerializeObject(v2));

            var v3 = client.GetFromMixedArg(2016,complexModel);
            Console.WriteLine("3---" + JsonConvert.SerializeObject(v3));


            var nest = new NestedModel()
            {
                Id = 999999,
                ComplexModel =complexModel
            };
            var v4 = client.PostFromMixedArg("this is my str", nest, complexModel);
            Console.WriteLine("4---" + JsonConvert.SerializeObject(v4));

            var v5 = client.PostFromMixedArg2("this is my str", complexModel, nest);
            Console.WriteLine("5---" + JsonConvert.SerializeObject(v5));

            Console.ReadLine();
        }
    }
}

here is the results:

consoletestresults

thx for the work

@lust4life
Copy link
Contributor Author

add support for multi endpoint use json config structure and refine ps cmd

maybe fix #10 #79

@lust4life
Copy link
Contributor Author

@faniereynders FYI.
i think the failed build in appveyor is because Microsoft.Net.Compilers package in (Api.Sample project) can not restore through nuget, but this project is just for a convenient test.

@faniereynders
Copy link
Member

@lust4life is there a way of fixing it? Ideally we would want he build to pass before merging the PR. Maybe we should create a Samples repo??

@lust4life
Copy link
Contributor Author

@faniereynders try a little,but appveyor‘s behavior makes me confused.finally just remove this sample project to make checks passed.

@faniereynders
Copy link
Member

great thanks @lust4life ! I will look at the changes in a bit. It's quite a lot 👍

In the meanwhile, I'm adding a samples repo over at https://github.com/WebApiProxy/samples. We need to get some samples going (also for POC purposes) so please could you upload your sample there in the respectable folder?

@lust4life
Copy link
Contributor Author

don't forget add w=1 to the url for changes review. i will add sample proj in the repo.

@faniereynders
Copy link
Member

what exactly does w=1 do? I'm a bit confused now

@lust4life
Copy link
Contributor Author

lust4life commented Jun 16, 2016

@lust4life
Copy link
Contributor Author

@faniereynders

add a pr for samples, the first two projects in samples can test this pr.
RestCode/samples#1

In the meanwhile, I'm adding a samples repo over at https://github.com/WebApiProxy/samples. We need to get some samples going (also for POC purposes) so please could you upload your sample there in the respectable folder?

@faniereynders
Copy link
Member

@lust4life dude you're a machine! 👍

@faniereynders
Copy link
Member

faniereynders commented Jun 17, 2016

@lust4life let's have a chat on https://gitter.im/WebApiProxy/vnext

@ghost
Copy link

ghost commented Aug 3, 2016

awesome~I really appreciate it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants