Coder Social home page Coder Social logo

cloudnimble / portablerest Goto Github PK

View Code? Open in Web Editor NEW
112.0 21.0 34.0 4.01 MB

A library for consuming REST APIs from Portable Class Libraries. Designed to be partially drop-in compatible with RestSharp.

Home Page: https://nuget.org/packages/PortableRest

C# 100.00%

portablerest's Introduction

PortableRest is a Portable Class Library for implementing REST API clients in other Portable Class Libraries. It leverages JSON.NET for rapid, customizable serialization, as well as the Microsoft.Bcl.Async library for awaitable execution on any platform. It is designed to be largely drop-in compatible with RestSharp, though you will need to make some changes and recompile if you are upgrading from that solution.

Works on all .NET Standard 2.0 platforms.

Design Goals

  • Be able to write one REST client wrapper that can be used on all current-generation Microsoft platforms (without the techniques we have to use for XamlEssentials).
  • Have more control over serialization of property names (so you're not limited to the "remove all dashes" convention of RestSharp).
  • Be able to have objects be easily serializable to local storage using standard techniques, without jumping through a lot of hoops.

What's New?

Version 3.0

  • Added constructor overload that accepts a custom HttpMessageHandler for all requests the HttpClient makes.
  • Added support for using the AsyncOAuth NuGet package for leveraging OAuth in your requests.
  • Added support for specifying the JsonSerializerSettings on a client-wide or per-request basis, with request-specific settings taking precedence.
  • Enhanced the SendAsync method to pass exceptions thrown by the serializer into the RestResponse.
  • BREAKING: The regular package is no longer being signed. If you need the signed version, install PortableRest.Signed instead.

Version 2.5

  • Ability to control parameter encoding. Example: RestRequest.AddParameter("test", someStream, ParameterEncoding.Base64);.
  • Ability to add request-specific headers. This is useful in situations where the value might change between requests, for example with expiring OAuth tokens. Example: RestRequest.AddHeader("X-Authorization", yourTokenHere);
  • The RestClient will now set the UserAgent for you if you do not set the property yourself. The format will be "YourAssemblyTitleAttributeValue Major.Minor.Revision (PortableRest Major.Minor.Revision)"
  • In addition, you can call RestClient.SetUserAgent<SomeTypeFromYourRestLibrary>(someString), which in the above example would replace YourAssemblyTitleAttributeValue with the contents of someString.

Version 2.4

  • Ability to control parameter encoding. Example: RestRequest.AddParameter("test", someStream, ParameterEncoding.Base64);.
  • Ability to add request-specific headers. This is useful in situations where the value might change between requests, for example with expiring OAuth tokens. Example: RestRequest.AddHeader("X-Authorization", yourTokenHere);
  • The RestClient will now set the UserAgent for you if you do not set the property yourself. The format will be "YourAssemblyTitleAttributeValue Major.Minor.Revision (PortableRest Major.Minor.Revision)"
  • In addition, you can call RestClient.SetUserAgent<SomeTypeFromYourRestLibrary>(someString), which in the above example would replace YourAssemblyTitleAttributeValue with the contents of someString.

Quick start

Install the NuGet package: Install-Package PortableRest, clone the repo, git clone git://github.com/cloudnimble/portablerest.git, or download the latest release.

If you are planning on redistributing your own PortableRest-based client, such as our http://gaug.es Client, you need to make sure your Portable profile does not use .NET 4.0, Silverlight 4.0, or Windows Phone 7.X. Having those platforms available will cause this package to fail to install. If you need support for those platforms, create an issue and we'll investigate the possibility of adding support.

Please see the unit tests project, Bing.RestClient, or Xbox.Music for examples of how to leverage PortableRest in your REST client.

Bug tracker

Have a bug? Please create an issue here on GitHub that conforms with necolas's guidelines.

https://github.com/CloudNimble/PortableRest/issues

Twitter account

Keep up to date on announcements and more by following CloudNimble on Twitter, @CloudNimble.

Blog

Read more detailed announcements, discussions, and more on The CloudNimble Dev Blog.

Author

Robert McLaws

Copyright and license

Copyright 2018-2020 CloudNimble, Inc.

The MIT License (MIT)

Copyright (c) 2018-2020 CloudNimble, Inc. and Robert McLaws

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

  • The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

portablerest's People

Contributors

chandu avatar matthewsannes avatar robertmclaws avatar scottisafool avatar shmuelie avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

portablerest's Issues

How to create and set a cookie

Tried adding a cookie to CookieContainer of RestClient as follows, but doesn't seem to work.
CookieContainer.Add(new Uri(BaseUrl), new Cookie("myCookie", "someValue", "/"));

Any help appreciated.

RestClient ignores proxy settings

As a mobile app developer I'm using Charles web proxy between my test devices and the internet to inspect network traffic. All PortableRest traffic does not go through the proxy if it is enabled on the device. It always uses a direct connection. If I disable direct internet access and make it available only through proxy, all client requests error out...

Please let me know if you need additional details.

Im running PortableRest PCL in Xamarin.iOS

Option to replace json library

As what you did with HttpMessageHandler, it would be great to substitute the json part as well with an interface. That way you can drop in for example service stack as a serializer for json.

Should handle null content for non-string type

The following new unit test demonstrates the issue and throws a null pointer exception against the current code base:

        [TestMethod]
        public async Task GracefullyHandleNullContentWithNonStringType()
        {
            // Setup
            var client = new RestClient { BaseUrl = BaseAddress };
            var request = new RestRequest("notsuccess/notfound");
            RestResponse<IEnumerable<Book>> response;

            // Execute
            using (WebApp.Start<WebApiStartup>(BaseAddress))
            {
                response = await client.SendAsync<IEnumerable<Book>>(request);
            }

            // Validate
            response.HttpResponseMessage.StatusCode.Should().Be(HttpStatusCode.NotFound);
            response.Content.Should().BeNull();
        }

Pull request with fix on the way.

How to send a request with void/no response model?

Hello there,

I know this may sound like a silly question, but since there is a lack of documentation, how can I execute a "SendAsync" request without a response object? Some of my APIs return nothing and this is making me get an exception within this library.

I tried it like this "await this.BuildClient().SendAsync(request);", but the result now carries an exception and the response status code is 400.

Overall, thank you so much for this project!

Cheers!

Async Question

Hi,

I am trying to use PortableRest to make an Async call to a Web API 2.2 Rest service from Xamarin Forms. Looks like a great project BTW.

I think I have some kind of deadlock / synchronisationcontext issue but I cannot work it out (newbie to async etc).

Can anyone please help?

My controller test method (removed any call to database) -

     public IEnumerable<ContentModel> GetTestRest()
    {
        return new List<ContentModel> {new ContentModel() {Categoryid = 1, Title = "Title"}};
    }

My Unit Test Passes -

    [TestMethod]
    public async Task TestRest()
    {
        MyNewsApiClient MyNewsApiClient = new MyNewsApiClient();

        var models = await MyNewsApiClient.TestRest();
        int count = models.Count;
        Assert.AreEqual(1, count);
    }

My PortableRest Proxy (PCL) Method -

    public async Task<List<ContentModel>> TestRest()
    {
        var request = new RestRequest();
        request.Resource = "Content/GetTestRest";

        return await ExecuteAsync<List<ContentModel>>(request);
    }

Xamarin Forms ContentPage (PCL) -

   public partial class NewsType1CP : ContentPage
{
    public NewsType1CP ()
    {
        InitializeComponent ();
    }

    protected override void OnAppearing ()
    {
        LoadData ();  // this is a sync call of an async method, not sure how else to approach, make OnAppearing async?
    }

    public async Task LoadData ()
    {
        Debug.WriteLine ("LoadData");

        HeaderLabel.Text = "Load Data!";

        MyNewsApiClient api = new MyNewsApiClient ();

        var cm = await api.TestRest ();
        // this will work on its own, control returns to this method - await api.GetDelay ();

        HeaderLabel.Text = "After! - ";

        NewsListView.ItemsSource = cm;
    }
}

The await to api.TestRest never results in HeaderLabel.After or ListView being set.

If I just add a Proxy Method which does not call PortableRest via - return await ExecuteAsync<List>(request);

           public async Task<bool> GetDelay ()
    {
        await Task.Delay (1000);
        return true;
    }

Then all "works".

Thanks for your help

Different assemblies referenced for different platform

Hey Robert,

For the Auth0 API client I am adding a reference to the PortableRest Nuget package. This includes a reference to the PortableRest.dll file.

When I create a Nuget package for the Auth0 API client, I specified that my Nuget package depends on the PortableRest package, so that PortableRest gets installed everytime a user adds a reference to the Auth0 API client Nuget package.

To test this I created a simple .NET4.6 Console application. When I add a reference to the Auth0 Nuget package, the PortablRest package gets installed as expected. This thing is however, that for the .NET 4.6 platform you add a reference not to PortableRest.DLL, but to PortableRest.Universal.DLL

This results in an exception when I try and run my application:

image

The core referenced assembly name should surely be the same, regardless of the platform? If they are not I will always run into this issue. Is there a reason why they are not the same?

PortableRest should not cause a deadlock if the library user waits for a task to complete.

When using PortableRest in a WebApi app to call other APIs, a call to Task.Result deadlocks. The solution is to always ConfigureAwait(false) when awaiting async methods in library code. For more information regarding the root cause and solution, watch the video at: http://channel9.msdn.com/Events/TechEd/Europe/2013/DEV-B318#fbid=

The following new unit test demonstrates this issue in the current code base: the call to client.ExecuteAsync<List<Book>>(request).Result; deadlocks:

        [TestMethod]
        public void async_libraries_like_portable_rest_should_not_deadlock_on_task_result()
        {
            // Setup
            var client = new RestClient { BaseUrl = BaseAddress };
            var request = new RestRequest("api/books");
            List<Book> response = null;

            // Execute
            using (WebApp.Start<WebApiStartup>(BaseAddress))
            {
                // Simulate ASP.NET and Windows Forms thread affinity
                WindowsFormsContext.Run(() =>
                {
                    // Should not deadlock on this call
                    response = client.ExecuteAsync<List<Book>>(request).Result;
                });
            }

            // Validate
            Assert.IsTrue(true, "If we got to this assertion, then we didn't deadlock on the call to ExecuteAsync.");
            response.Should().NotBeNull();
            response.Count().Should().Be(5);
        }

A pull request with the fix is on the way.

Newtonsoft.Json not downloaded anymore with 3.0 release

I've updated the package to 3.0 from Xamarin nuget into my project and now my code is not compiling anymore because the Newtonsoft.Json package has vanished.
In fact, the dependency is not listed anymore from nuget info.
snip20140816_6

Deserialisation does not use JsonSerializerSettings

In RestClient.cs, line 404, the call to DeserializeObject is not including the JsonSerializerSettings attached to restRequest:

return JsonConvert.DeserializeObject<T>(responseContent);

looks like it should be

return JsonConvert.DeserializeObject<T>(responseContent, restRequest.JsonSerializerSettings);

I'm seeing this express as a bug where the custom settings I use for TypeNameHandling or SerializationBinder are being ignored.

Just tried this change on a cloned copy and it fixed the problem.

Throwing a Bad Request for all exceptions is misleading

Currently, when the Rest Client encounters an exception, it wraps it in a RestResponse with a Bad Request code.

This is misleading, especially since there are no sanity checks when adding Url segments or query strings (e.g. is the value null?). This results in exceptions that are not caused by the HTTP client itself, and so deserves to be wrapped in PortableRestException - or at least just be thrown as-is.

Offending code: https://github.com/advancedrei/PortableRest/blob/master/src/PortableRest/RestClient.cs#L193

Can not add Newtonsoft.Json.Linq.JValue to Newtonsoft.Json.Linq.JObject

When calling with json contenttype I am getting an error when adding some parameters:
Can not add Newtonsoft.Json.Linq.JValue to Newtonsoft.Json.Linq.JObject

I took a look and the error is happening with Json.newtonsoft when trying to do new JObject("somevalue"). This is because a string is a JValue type my guess, I tried it in my own code and it works if I change JObject to JValue.

image

here is the file:
https://github.com/CloudNimble/PortableRest/blob/90a1b4fe44b2a67c654b6cdf6966e429c81276c3/src/PortableRest/RestRequest.cs

System.ArgumentException: Can not add Newtonsoft.Json.Linq.JValue to Newtonsoft.Json.Linq.JObject.
at Newtonsoft.Json.Linq.JObject.ValidateToken (Newtonsoft.Json.Linq.JToken o, Newtonsoft.Json.Linq.JToken existing) [0x0002f] in :0
at Newtonsoft.Json.Linq.JContainer.InsertItem (System.Int32 index, Newtonsoft.Json.Linq.JToken item, System.Boolean skipParentCheck) [0x00054] in :0
at Newtonsoft.Json.Linq.JObject.InsertItem (System.Int32 index, Newtonsoft.Json.Linq.JToken item, System.Boolean skipParentCheck) [0x0000d] in :0
at Newtonsoft.Json.Linq.JContainer.AddInternal (System.Int32 index, System.Object content, System.Boolean skipParentCheck) [0x00050] in :0
at Newtonsoft.Json.Linq.JContainer.Add (System.Object content) [0x0000c] in :0
at Newtonsoft.Json.Linq.JObject..ctor (System.Object content) [0x00011] in :0
at PortableRest.RestRequest.GetRequestBody () [0x00189] in :0
at PortableRest.RestClient+d__39`1[T].MoveNext () [0x00322] in :0
--- End of stack trace from previous location where exception was thrown ---

Expose JsonSerializerSettings somehow

It is important that we have more control over Json deserialization. The method JsonConvert.DeserializeObject has 3 overloads, it would be nice to allow to use these overloads for edge cases.

Or there is a way and I am missing something?

GetEncodedValue doesn't check for null values

When adding AddParameter and one of the values is null it will choose to encode and make PortableRest explode on GetEncodedValue (null pointer exception).

Resolution:
Add a null check.

Add IgnoreBlankParameters option

Add an option that, if set to true, does not add new items to the internal parameters collections if the item is null or whitespace. This would simplify client code by moving null checks into the core runtime.

Should not add trailing slash when Resource URI is null

The following new unit test demonstrates the issue in the current code base:

        [TestMethod]
        public void BuildResourceUriWhereResourceUriIsNull()
        {
            var request = new RestRequest();

            Assert.AreEqual("https://www.googleapis.com/discovery/v1/apis?&name=adexchangebuyer", 
                request.GetResourceUri("https://www.googleapis.com/discovery/v1/apis?&name=adexchangebuyer").ToString());
        }

and fails with the following message:

Assert.AreEqual failed. Expected:<https://www.googleapis.com/discovery/v1/apis?&name=adexchangebuyer>. Actual:<https://www.googleapis.com/discovery/v1/apis?&name=adexchangebuyer/>. 

Pull request with fix on its way.

Slashes are not combined properly when building Resource URI

The following tests reproduce this issue:

        [TestMethod]
        public void BuildResourceUriWhereBaseUriAndResourceHaveSlashes()
        {
            var request = new RestRequest("/test");
            Assert.AreEqual("http://test.com/test", request.GetResourceUri("http://test.com/").ToString());
        }

Result: Assert.AreEqual failed. Expected:http://test.com/test. Actual:http://test.com//test.

        [TestMethod]
        public void BuildResourceUriWhereBaseUriHasTrailingSlash()
        {
            var request = new RestRequest("test");
            Assert.AreEqual("http://test.com/test", request.GetResourceUri("http://test.com/").ToString());
        }

Result: Assert.AreEqual failed. Expected:http://test.com/test. Actual:http://test.com//test.

RestClient should implement IDisposable (and Dispose(bool) from HttpClient)

HttpClient is disposable, as it deals with unmanaged resources, however it cannot currently be desposed by applications using PortableRest since RestClient doesn't implement IDisposable. This has the potential to cause issues in some circumstances where RestClient instances are rapidly created and discarded (but not disposed).

Examples?

It would be nice to at least see some basic examples of how to use this library. So far, not much luck.

Ability to set Timeout on HttpClient

Would it be possible to allow the Timeout property of the internal HttpClient to be set? We have one or two calls that can take longer than 60 seconds in some circumstances before a response is sent. These requests are currently getting cancelled before completion.

After upgrading to 3.0.0-RC1, getting Could not determine JSON object type for type <>__AnonType1`2[System.String,System.String]..

I've upgraded to the latest 3.0.0-RC1 drop from nuget and now I'm getting the error:

Could not determine JSON object type for type <>__AnonType12[System.String,System.String]..

I'm creating a simple request like this:

RestRequest request = new RestRequest(resource, HttpMethod.Post);
request.ContentType = ContentTypes.Json;
request.AddParameter("body", new {
    username = "test",
    password = "test"
});
RestResponse<Customer> response = await this.RestClient.SendAsync<Customer>(request);

I'm running this on Xamarin.iOS and Xamarin.Android. Any help is appreciated as this breaks all requests that were previously working.

Stacktrace:
Could not determine JSON object type for type <>__AnonType12[System.String,System.String].. Please try again. 2014-07-04 13:03:26.992 TestProjectClientiOS[4842:70b] at Newtonsoft.Json.Linq.JValue.GetValueType (Nullable1 current, System.Object value) [0x00000] in :0
at Newtonsoft.Json.Linq.JValue..ctor (System.Object value) [0x00000] in :0
at PortableRest.RestRequest.GetRequestBody () [0x00000] in :0
at PortableRest.RestClient+d__111[TestProject.Client.Customer].MoveNext () [0x00000] in <filename unknown>:0 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000b] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Runtime.ExceptionServices/ExceptionDispatchInfo.cs:62 at System.Runtime.CompilerServices.TaskAwaiter1[PortableRest.RestResponse1[TestProject.Client.Customer]].GetResult () [0x00034] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Runtime.CompilerServices/TaskAwaiter_T.cs:59 at TestProject.Client.ClientApi+<SignIn>c__async2.MoveNext () [0x000ac] in /path/TestProject.Client/TestProject.Client/Api/ClientApi.cs:54 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000b] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Runtime.ExceptionServices/ExceptionDispatchInfo.cs:62 at System.Runtime.CompilerServices.TaskAwaiter1[TestProject.Client.ApiAuthenticationResult`1[TestProject.Client.Customer]].GetResult () [0x00034] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Runtime.CompilerServices/TaskAwaiter_T.cs:59

2 RestRequest using 1 RestClient throwing exception

I am experiencing an error when trying to ExecuteAsync two different RestRequest objects with the same RestClient. A similar situation to the following:

    public async Task ExecuteAsyncOfTReturnsDeserializedContentOfT()
    {
        // Setup
        var client = new RestClient { BaseUrl = BaseAddress };
        var request = new RestRequest("api/books");
        List<Book> response;

        // Execute
        using (WebApp.Start<WebApiStartup>(BaseAddress))
        {
            response = await client.ExecuteAsync<List<Book>>(request);
        }

        // Validate
        response.Should().NotBeNull();
        response.Count().Should().Be(5);

        var request2 = new RestRequest("api/books");
        List<Book> response2;

        // Execute
        using (WebApp.Start<WebApiStartup>(BaseAddress))
        {
            response2 = await client.ExecuteAsync<List<Book>>(request2);
        }

        // Validate
        response2.Should().NotBeNull();
        response2.Count().Should().Be(5);
    }

I am getting the following exception. Am I doing something wrong?

This instance has already started one or more requests. Properties can only be modified before sending the first request.

at System.Net.Http.HttpClientHandler.EnsureModifiability () [0x0000b] in /Developer/MonoTouch/Source/mono/mcs/class/System.Net.Http/System.Net.Http/HttpClientHandler.cs:64
at System.Net.Http.HttpClientHandler.set_AllowAutoRedirect (Boolean value) [0x00000] in /Developer/MonoTouch/Source/mono/mcs/class/System.Net.Http/System.Net.Http/HttpClientHandler.cs:74
at PortableRest.RestClient.ConfigureHandler (System.Net.Http.HttpMessageHandler handler) [0x00000] in :0
at PortableRest.RestClient+d__11`1[System.String].MoveNext () [0x00000] in :0

Content is Null on Unauthorized and Forbidden status code

Converting code from RestSharp we've just noticed that when the server response is Unauthorized or Forbidden, even if it returns a content (a json descripting the error, in our case) the RestResponse.content is null.

We are basically doing stuff like this:

var response = await client.SendAsync(request);

and based on the response.HttpResponseMessage.StatusCode value we deserialize the response.Content.

Is this a known issue?

Thanks
Luigi

interfaces for IRestClient and IRestRequest

Hello,

Do you think its too late to add interfaces for IRestClient and IRestRequest client so that its easily mockable without hitting an actual web server. I would like to use mock to test REST api.

Support for Visual Studio 2013

Since VS2013 dropped support to Windows Phone 7.5 and Silverlight 4, it doesn´t allow me reference this library. I tried using NuGet and VS2013 RC

Parse response content if server returns error status code

The web service I'm developing against returns the status code 400 for a bad request. The content then contains a JSON message with additional error details. This seems to be recommended behaviour, e.g. see: http://stackoverflow.com/questions/3290182/rest-http-status-codes

However, the PortableRest library does not return the content of the response message in case the status code does not indicate success:

  • ExecuteAsync() throws an exception through EnsureSuccessStatusCode().
  • SendAsync() in turn calls GetRawResponseContent(), which again only reads the response if the status code indicates success: response.IsSuccessStatusCode

Is there a way to get the actual error message in case the request was not successful and the response status code is set accordingly to bad request?

Getting "Error getting value from 'ReadTimeout' on 'System.IO.FileStream'" when using AddFileParameter

I am using the new AddFileParameter to read a file from disk using FileStream, but when I try and make an HTTP POST, I get a "Error getting value from 'ReadTimeout' on 'System.IO.FileStream'" exception.

It seems that it is because it is trying to serialize everything to a string and pass it using a StringContent object.

I do not think this is the correct approach. For multipart data your should pass a MultipartFormDataContent instance.

Do you have an example of how to do file uploads with PortableRest, because I might just be missing something...

PortableRest 4.0 Alpha-1

Hi,

I know I am working on an alpha release, but this one seems the only one that I can add to my Xamarin.iOS and Xamarin.Android project (I am using shared library so I cannot use the 3.x versions as they dont have a xamarin supported nuget as far as I know). So one thing I noted that was broken is that the AddQueryString and AddUrlSegment basically double up. Meaning if I add a new query string it will double &key=value&samekey=samevalue (I cannot see it in the debugger at first but after the response happens when I go over the request somehow there a duplicate query string added). For now I am basically just adding it manually to the request string. This doesnt seem to happen for AddParameter.

Kind regards,
Robert Al Malak

UWP (Windows 10) gives File Not Found on System.Net

was playing with upgrading a Windows Phone 8.1 (RT) project to UWP but when I run it i'm getting an error in the constructor of my inherited RestClient that it cannot find system.net (full error below).

I don't know enough about the changes between 8.1 and 10 to know what I'm doing wrong, if I had to guess I would say that there's a conflict between the library referenced in the original portable library (4.0) and UWP (I think 4.5?) can I perhaps do an assembly redirect?

Error message follows:

An exception of type 'System.IO.FileNotFoundException' occurred in MyApp.Core.dll but was not handled in user code

Additional information: Could not load file or assembly 'System.Net, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, Retargetable=Yes' or one of its dependencies. The system cannot find the file specified.

It ignores Parameters

The RestRequest.AddParameter add the parameter to a list but doesn't do anything with it.

It should add to query string

File Upload Support?

I could not find a standard mechanism to upload files with this library, do I have a blind spot?

Using HttpMethod.Delete is triggering a NullReferenceException

Using the following code will produce a NullReferenceException. Originally I thought it was because I was not supplying a body object (since HTTP DELETE shouldn't need one), but supplying a new object() doesn't help.

    protected async Task HttpDelete(string url)
    {
        var restClient = new RestClient();
        restClient.BaseUrl = Client.BaseUrl.ToString();
        restClient.AddHeader("X-ApiKey", Client.ApiKey.ToString());

        if (!String.IsNullOrEmpty(Client.Token))
            restClient.AddHeader("X-AuthToken", Client.Token);

        var request = new RestRequest(url, HttpMethod.Delete);
        request.ContentType = ContentTypes.Json;

        var response = await restClient.SendAsync<object>(request);
        if (response.Exception != null)
            throw new Exception("Exception retrieving response.", response.Exception);

        response.HttpResponseMessage.EnsureSuccessStatusCode();
    }

The stack trace is not revealing precisely where the problem is occurring, however.

System.Exception: Exception retrieving response. ---> System.NullReferenceException: Object reference not set to an instance of an object.
Result StackTrace:  
at Microsoft.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at Microsoft.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccess(Task task)
   at PortableRest.RestClient.<SendAsync>d__6``1.MoveNext()
 --- End of inner exception stack trace ---
    at Microsoft.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at Microsoft.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccess(Task task)
   at Fi.Partners.Api.Client.DownloadBundlesExtension.DownloadBundlesApi.<Delete>d__10.MoveNext() in d:\Projects\Partners\MobileApp\API\Fi.Partners.Api.Client.Mobile\ApiExtensions\DownloadBundlesExtension.cs:line 55
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
   at Fi.Partners.Api.Client.Tests.DownloadBundleTest.<CreatedBundleShouldExistInAll>d__e.MoveNext() in d:\Projects\Partners\MobileApp\API\Fi.Partners.Api.Client.Tests\DownloadBundleTest.cs:line 79
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()

EDIT: The URL being called does not return a response body when a deletion is successful, just a 204 response code (No Content).

Method not found Exception

Working on a Windows 8.1 app. I've created a PCL DataAccess library targeting Windows 8.1, Windows Phone 8, .Net 4.5.1.

I added PortableREST to the library w/o issue. However, when I tell the client to ExecuteAsync I'm met with this exception detail:

System.MissingMethodException was unhandled by user code
  HResult=-2146233069
  Message=Method not found: 'Void System.Net.Http.HttpClientHandler.set_AutomaticDecompression(System.Net.DecompressionMethods)'.
  Source=PortableRest
  StackTrace:
       at PortableRest.RestClient.<ExecuteAsync>d__2`1.MoveNext()
       at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
       at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start[TStateMachine](TStateMachine& stateMachine)
       at PortableRest.RestClient.ExecuteAsync[T](RestRequest restRequest)

Any information you could give me on what might be going wrong would be most welcome. Thanks

edit
I should add that I'm using the example code from http://advancedrei.com/blogs/development/introducing-portablerest-v2-cross-platform-rest-client-for-dotnet-apps (minus the Items property on the contract, since the 'Api' object isn't shown) when I get this error.

SetUserAgent causes app to hang

Hello,

I am having this problem where my xamarin app is hanging when calling SetUserAgent.

var client = new RestClient() { BaseUrl = baseUrl };
client.JsonSerializerSettings = new JsonSerializerSettings();
client.JsonSerializerSettings.ContractResolver = new LowercaseJsonSerializer.LowercaseContractResolver();
client.JsonSerializerSettings.Converters.Add(new CustomDateTimeConverter());
client.SetUserAgent("Balln");

If I omit the call to SetUserAgent, i am getting an exception -- The assembly containing the class inheriting from PortableRest.RestClient must have an AssemblyTitle attribute specified.

Any idea?

Using PortableRest on iOS fails with user agent.

When using RestClient on iOS simulator everything works great, but when going to the device:

System.Exception: The assembly containing the class 
inheriting from PortableRest.RestClient must have an 
AssemblyTitle attribute specified.

I am not deriving RestClient, I am using it directly. Also, my app + all referenced assemblies all have the AssemblyTitle set in AssemblyInfo.cs.

When setting the user agent manually on the client, I get:

System.ArgumentException: This header must 
be modified with the appropiate property.

What do I do?

AddParameter vs AddQueryString

In PortableRest, you can still use AddParameter with a GET request, but it will not be added to the querystring, and there will no indication other than maybe the request failing or returning the wrong thing.

As an example, this test will fail because the API is expecting a ?term=kepp in the URL.

[TestFixture]
public class ParameterTest
{
    [Test]
    public async void Example()
    {
        var rest = new RestClient();
        var req = new RestRequest("http://rxnav.nlm.nih.gov/REST/approximateTerm");
        req.AddHeader("Accept", "application/json");
        req.AddParameter("term","kepp");
        var result = await rest.ExecuteAsync<object>(req);
        Assert.That(result, Is.Not.Null);
    }
}

However, this works:

[TestFixture]
public class ParameterTest
{
    [Test]
    public async void Example()
    {
        var rest = new RestClient();
        var req = new RestRequest("http://rxnav.nlm.nih.gov/REST/approximateTerm");
        req.AddHeader("Accept", "application/json");
        req.AddQueryString("term","kepp");
        var result = await rest.ExecuteAsync<object>(req);
        Assert.That(result, Is.Not.Null);
    }
}

It would be nice if:
a) AddParameter would create querystring parameters on GET requests
or
b) An exception was thrown when attempting to execute a GET request after AddParameter has been used.

Incorrectly throws ArgumentNullException

SendAsync<> throws ArgumentNullException (from RestResponse) when a NameResolutionFailure Exception occurs from the response, instead of allowing that error to bubble.

Authentication Support in PortableRest 2.6

So PortableRest is at the point where it is lightweight and stable, and handles basic scenarios very well. It's time to start adding in "authenticated" HTTP requests into the pipeline.

I am a firm believer that this library should be as simple and intuitive as humanly possible. So I see 2 approaches for handling auth in the library.

One is in [[https://github.com//pull/15|PR #15]], which I initially was not thrilled with, but is starting to grow on me. It may not be the route we choose to take, but it is clearly named and well implemented. In this architecture, you have separate classes that only deal with authentication, each implementing IAuthenticator, as well as an "Authenticator" property on the RestClient. Then, at the beginning of each request, you call "Authenticator.Authenticate()". It would be up to that "Authenticate" method to determine if authentication is even necessary for that call, inject the proper headers into the request, etc.

The other I have in mind, which really only has subtle differences in implementation, but is closer to how you implement PortableRest for your APIs in the first place, would be to subclass RestClient. So you would have:

  • BasicAuthRestClient
  • OAuthRestClient
  • JwtRestClient
  • Etc.

In this pattern, the RestClient constructors would be different, allowing you to pass in ClientKey/ClientSecret in the case of OAuth & JWT, and the XXXRestClient would manage how it handles tokens, signatures, and other details inside that class itself. Then the class implementing the API (say if you are building Yet Another Twitter API) would change to inherit from OAuthRestClient, instead of just RestClient. That change would pick up all of the necessary functionality with no additional code.

Regarding how all that will be implemented, I have been working with the guys at Auth0.com to improve their libraries for dealing with JWT in the ASP.NET/OWIN pipeline. That code will include some extensions to turn JWT attributes into .NET claims, and that code could be leveraged in PortableRest too.

Because of that, some of the implementations will likely be add-on assemblies, because I do not want to have the core lib take a dependency on anything more than it already has to. So keep that in mind when you weigh in on which approach should be used.

At the end of the day, if you are building reusable REST APIs to post to NuGet and using PortableRest as the base, NONE of these options should surface to the developer that downloads that API off of NuGet and starts using it. Just like with my Xbox.Music client, the end developer should not have to deal with exoired tokens or anything else... the code implementing PortableRest should automatically handle that for you. So just keep that in mind as well.

Looking forward to your thoughts... - Robert

Ignore SSL issues

When using Windows.Web.Http.HttpClient you can do stuff like this:

        private HttpClient CreateClient()
        {
            var filter = new HttpBaseProtocolFilter();
            if (_env.IgnoreSslProblems)
            {
                filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.IncompleteChain);
                filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Expired);
                filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted);
                filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName);
            }
            return new HttpClient(filter);
        }

Is it possible to do this with PortableRest? Or would we have to create a (less portable) fork?

NullReferenceException if returned Content is null and success status code

Using the latest 3.0.1 version of Portable Rest.

When I call SendAsync() that does a PUT request, I get back a 400 Bad Request by the Portable Rest library. However, I had Fiddler running and I can see that the request actually succeeded (200) and there was no content returned.

Digging in to the source , it seems to me that the exception occurs in this method when it does a response.Content.ReadAsStringAsync() if Content is null -

In RestClient.cs -

private static async Task GetRawResponseContent([NotNull] HttpResponseMessage response)
{
//RWM: Explicitly check for NoContent... because the request was successful but there is nothing to do.
if (response.IsSuccessStatusCode && response.StatusCode != HttpStatusCode.NoContent)
{
return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
}
return null;
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.