3

I am trying to Consume a Web Service using HttpClient in .NET and after I did all steps mentioned in msdn.

I get the following exception:

An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set.

Here is my class:

public class Customer
{
    public int id { get; set; }
    public string id_default_group { get; set; }
    public string id_lang { get; set; }
    public string newsletter_date_add { get; set; }
    public string ip_registration_newsletter { get; set; }
    public string last_passwd_gen { get; set; }
    public string secure_key { get; set; }
    public string deleted { get; set; }
    public string passwd { get; set; }
    public string lastname { get; set; }
    public string firstname { get; set; }
    public string email { get; set; }
    public string id_gender { get; set; }
    public string birthday { get; set; }
    public string newsletter { get; set; }
    public string optin { get; set; }
    public string website { get; set; }
    public string company { get; set; }
    public string siret { get; set; }
    public string ape { get; set; }
    public string outstanding_allow_amount { get; set; }
    public string show_public_prices { get; set; }
    public string id_risk { get; set; }
    public string max_payment_days { get; set; }
    public string active { get; set; }
    public string note { get; set; }
    public string is_guest { get; set; }
    public string id_shop { get; set; }
    public string id_shop_group { get; set; }
    public string date_add { get; set; }
    public string date_upd { get; set; }
    public string reset_password_token { get; set; }
    public string reset_password_validity { get; set; }

}

class Program
{

    static void ShowProduct(Customer customer)
    {
        Console.WriteLine($"Email: {customer.email}\tFirst Name: {customer.firstname}");
    }

    static async Task<Uri> CreateCustomerAsync(Customer customer)
    {
        HttpClient client = new HttpClient();
        HttpResponseMessage response = await client.PostAsJsonAsync("api/customers/1?output_format=JSON", customer);
        response.EnsureSuccessStatusCode();

        // return URI of the created resource.
        return response.Headers.Location;
    }
    static void Main()
    {
        RunAsync().Wait();
    }
    static async Task RunAsync()
    {
        NetworkCredential hd = new NetworkCredential("INHFTLZLMLP1TUTJE7JL9LETCCEW63FN", "");
        HttpClientHandler handler = new HttpClientHandler {Credentials = hd };
        HttpClient client = new HttpClient(handler);

        client.BaseAddress = new Uri("http://localhost:8080/newprestashop/");
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

            try
            {

                Customer customer = new Customer();
                var url = await CreateCustomerAsync(customer);
                // Get the product
                customer = await GetProductAsync(url.PathAndQuery);
                ShowProduct(customer);


            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }

            Console.ReadLine();
        }

    static async Task<Customer> GetProductAsync(string path)
    {
        Customer customer = null;
        HttpClient client = new HttpClient();
        HttpResponseMessage response = await client.GetAsync(path);
        if (response.IsSuccessStatusCode)
        {
            customer = await response.Content.ReadAsAsync<Customer>();
        }
        return customer;
    }

}
}
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Zero One
  • 47
  • 1
  • 1
  • 5
  • Are you sure your web service is up and running at http://localhost:8080? I would launch the web api project and add a break point at the start of the method (index) of the controller (newprestashop) you are trying to hit. Then, make your call from your client. – Mitch Stewart May 05 '17 at 16:41
  • i test in post man it work great – Zero One May 05 '17 at 16:45

3 Answers3

4

BaseAddress is there so that you can make all the calls relative to the the BaseAddress. It works, you just need to know some of the idiosyncrasies of BaseAddress Why is HttpClient BaseAddress not working?

But your problem is that you are instantiating a new HttpClient in each method.

static async Task<Uri> CreateCustomerAsync(Customer customer)
{
    HttpClient client = new HttpClient();
    //you never set the BaseAddress 
    //or the authentication information
    //before making a call to a relative url!
    HttpResponseMessage response = await client.PostAsJsonAsync("api/customers/1?output_format=JSON", customer);
    response.EnsureSuccessStatusCode();

    // return URI of the created resource.
    return response.Headers.Location;
}

A better way would be to wrap the HttpClient call in a class and it up in the constructor, then share it in any of your methods

    public WrapperClass(Uri url, string username, string password, string proxyUrl = "")
    {
        if (url == null)
            // ReSharper disable once UseNameofExpression
            throw new ArgumentNullException("url");
        if (string.IsNullOrWhiteSpace(username))
            // ReSharper disable once UseNameofExpression
            throw new ArgumentNullException("username");
        if (string.IsNullOrWhiteSpace(password))
            // ReSharper disable once UseNameofExpression
            throw new ArgumentNullException("password");
        //or set your credentials in the HttpClientHandler
        var authenticationHeaderValue = new AuthenticationHeaderValue("Basic",
            // ReSharper disable once UseStringInterpolation
            Convert.ToBase64String(Encoding.UTF8.GetBytes(string.Format("{0}:{1}", username, password))));

        _httpClient = string.IsNullOrWhiteSpace(proxyUrl)
            ? new HttpClient
            {
                DefaultRequestHeaders = { Authorization = authenticationHeaderValue },
                BaseAddress = url
            }
            : new HttpClient(new HttpClientHandler
            {
                UseProxy = true,
                Proxy = new WebProxy
                {
                    Address = new Uri(proxyUrl),
                    BypassProxyOnLocal = false,
                    UseDefaultCredentials = true
                }
            })
            {
                DefaultRequestHeaders = { Authorization = authenticationHeaderValue },
                BaseAddress = url
            };

        _httpClient.DefaultRequestHeaders.Accept.Clear();
        _httpClient.DefaultRequestHeaders.AcceptEncoding.Clear();
        _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    }

    public async Task<Member> SomeCallToHttpClient(string organizationId)
    {
        var task = await _httpClient.GetStringAsync(<your relative url>));

        return JsonConvert.DeserializeObject<SomeType>(task,
            new JsonSerializerSettings {ContractResolver = new CamelCasePropertyNamesContractResolver()});
    }
Fran
  • 6,440
  • 1
  • 23
  • 35
3

I bet you need the complete url address. The url is not relative to the caller when using HttpClient.

static async Task<Uri> CreateCustomerAsync(Customer customer)
{
   HttpClient client = new HttpClient();
   HttpResponseMessage response = await client.PostAsJsonAsync("http://www.fullyqualifiedpath.com/api/customers/1?output_format=JSON", customer);
   response.EnsureSuccessStatusCode();

   // return URI of the created resource.
   return response.Headers.Location;
}
Hakan Fıstık
  • 16,800
  • 14
  • 110
  • 131
Ross Bush
  • 14,648
  • 2
  • 32
  • 55
  • works great the exception is gone but it gives another " Response status code does not indicate success: 401 (Unauthorized)." – Zero One May 05 '17 at 16:42
  • That means you need to authenticate prior to making your api call. The endpoint was reached and rejected due to lack of authorization. – Ross Bush May 05 '17 at 16:51
  • Your authorization problem is the same problem as your BaseAddress one. you instantiate HttpClient and never set the values. See my answer. – Fran May 05 '17 at 17:20
  • I would actually give the answer to @Fran. I solved your immediate problem, however, his answer solves with a better overall solution. – Ross Bush May 05 '17 at 17:45
0

If you copied the URL from somewhere, check it for non-visible characters. Paste the URL string into a browser, and see if anything gets escaped oddly.

I had this same problem with a seemingly normal URL. When I pasted it into a browser and tried to retrieve it, the beginning of it turned into this:

%E2%80%8Bhttps

There was some non-visible Unicode character at the start of the string that the browser reveled by encoding it.

Back in code, when I put my cursor at what looked like the start of the string and pressed "Backspace," the cursor did not appear to move. In reality, it was deleting that non-visible character.

It worked fine after that.

Deane
  • 8,269
  • 12
  • 58
  • 108