Anirban Ghosh
Anirban Ghosh

Reputation: 57

Sending Data to WEB API function from Code behind C#

I have created Web API Services. What I am trying to do is to call that API function, namely SaveSession(string data), from code behind button click, and to pass the entire form collection data as parameter in string format. When I call the api's uri through webclient.uploadstring(url,string); It is calling the web service but the parameter is not getting passed. Pls help.

Upvotes: 1

Views: 4112

Answers (1)

Oppositional
Oppositional

Reputation: 11211

Instead of using a controller action method that accepts a string, you can instead read the form-url-encoded content posted to the controller.

In the example below, the SessionController exposes a SaveSession() method that accepts a POST of form-url-encoded content and then reads the session data as a collection of KeyValuePair instances.

The example client builds a list of key-value pairs and then uses a HttpClient instance to post the FormUrlEncodedContent to the web API controller method.

Example SessionController:

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;

namespace MvcApplication1.Controllers
{
    public class SessionController : ApiController
    {
        /// <summary>
        /// Saves specified the session data.
        /// </summary>
        /// <returns>
        /// A <see cref="HttpResponseMessage"/> that represents the response to the requested operation.
        /// </returns>
        [HttpPost()]
        public HttpResponseMessage SaveSession()
        {
            // Ensure content is form-url-encoded
            if(!IsFormUrlEncodedContent(this.Request.Content))
            {
                return this.Request.CreateResponse(HttpStatusCode.BadRequest);
            }

            // Read content as a collection of key value pairs
            foreach (var parameter in ReadAsFormUrlEncodedContentAsync(this.Request.Content).Result)
            {
                var key     = parameter.Key;
                var value   = parameter.Value;

                if(!String.IsNullOrEmpty(key))
                {
                    // Do some work to persist session data here
                }
            }

            return this.Request.CreateResponse(HttpStatusCode.OK);
        }

        /// <summary>
        /// Determines whether the specified content is form URL encoded content.
        /// </summary>
        /// <param name="content">
        /// The type that the <see cref="IsFormUrlEncodedContent(HttpContent)"/> method operates on.
        /// </param>
        /// <returns>
        /// <see langword="true"/> if the specified content is form URL encoded content; otherwise, <see langword="false"/>.
        /// </returns>
        public static bool IsFormUrlEncodedContent(HttpContent content)
        {
            if (content == null || content.Headers == null)
            {
                return false;
            }

            return String.Equals(
                content.Headers.ContentType.MediaType, 
                FormUrlEncodedMediaTypeFormatter.DefaultMediaType.MediaType, 
                StringComparison.OrdinalIgnoreCase
            );
        }

        /// <summary>
        /// Write the HTTP content to a collection of name/value pairs as an asynchronous operation.
        /// </summary>
        /// <param name="content">
        /// The type that the <see cref="ReadAsFormUrlEncodedContentAsync(HttpContent)"/> method operates on.
        /// </param>
        /// <returns>The <see cref="Task"/> object representing the asynchronous operation.</returns>
        /// <remarks>
        /// The <see cref="ReadAsFormUrlEncodedContentAsync(HttpContent, CancellationToken)"/> method 
        /// uses the <see cref="Encoding.UTF8"/> format (or the character encoding of the document, if specified) 
        /// to parse the content. URL-encoded characters are decoded and multiple occurrences of the same form 
        /// parameter are listed as a single entry with a comma separating each value.
        /// </remarks>
        public static Task<IEnumerable<KeyValuePair<string, string>>> ReadAsFormUrlEncodedContentAsync(HttpContent content)
        {
            return ReadAsFormUrlEncodedContentAsync(content, CancellationToken.None);
        }

        /// <summary>
        /// Write the HTTP content to a collection of name/value pairs as an asynchronous operation.
        /// </summary>
        /// <param name="content">
        /// The type that the <see cref="ReadAsFormUrlEncodedContentAsync(HttpContent, CancellationToken)"/> method operates on.
        /// </param>
        /// <param name="cancellationToken">
        /// The cancellation token used to propagate notification that the operation should be canceled.
        /// </param>
        /// <returns>The <see cref="Task"/> object representing the asynchronous operation.</returns>
        /// <remarks>
        /// The <see cref="ReadAsFormUrlEncodedContentAsync(HttpContent, CancellationToken)"/> method 
        /// uses the <see cref="Encoding.UTF8"/> format (or the character encoding of the document, if specified) 
        /// to parse the content. URL-encoded characters are decoded and multiple occurrences of the same form 
        /// parameter are listed as a single entry with a comma separating each value.
        /// </remarks>
        public static Task<IEnumerable<KeyValuePair<string, string>>> ReadAsFormUrlEncodedContentAsync(HttpContent content, CancellationToken cancellationToken)
        {
            return Task.Factory.StartNew<IEnumerable<KeyValuePair<string, string>>>(
                (object state) =>
                {
                    var result  = new List<KeyValuePair<string, string>>();

                    var httpContent = state as HttpContent;

                    if (httpContent != null)
                    {
                        var encoding    = Encoding.UTF8;
                        var charSet     = httpContent.Headers.ContentType.CharSet;

                        if (!String.IsNullOrEmpty(charSet))
                        {
                            try
                            {
                                encoding    = Encoding.GetEncoding(charSet);
                            }
                            catch (ArgumentException)
                            {
                                encoding    = Encoding.UTF8;
                            }
                        }

                        NameValueCollection parameters = null;

                        using (var reader = new StreamReader(httpContent.ReadAsStreamAsync().Result, encoding))
                        {
                            parameters = HttpUtility.ParseQueryString(reader.ReadToEnd(), encoding);
                        }

                        if (parameters != null)
                        {
                            foreach(var key in parameters.AllKeys)
                            {
                                result.Add(
                                    new KeyValuePair<string, string>(key, parameters[key])
                                );
                            }
                        }
                    }

                    return result;
                },
                content,
                cancellationToken
            );
        }
    }
}

Example Calling Client:

using System;
using System.Collections.Generic;
using System.Net.Http;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var client = new HttpClient())
            {
                // Initialize HTTP client
                client.BaseAddress  = new Uri("http://localhost:26242/api/", UriKind.Absolute);
                client.Timeout      = TimeSpan.FromSeconds(10);

                // Build session data to send
                var values          = new List<KeyValuePair<string, string>>();

                values.Add(new KeyValuePair<string, string>("Item1", "Value1"));
                values.Add(new KeyValuePair<string, string>("Item2", "Value2"));
                values.Add(new KeyValuePair<string, string>("Item3", "Value3"));

                // Send session data via POST using form-url-encoded content
                using (var content = new FormUrlEncodedContent(values))
                {
                    using (var response = client.PostAsync("session", content).Result)
                    {
                        Console.WriteLine(response.StatusCode);
                    }
                }
            }
        }
    }
}

I typically have the IsFormUrlEncodedContent and ReadAsFormUrlEncodedContentAsync methods as extension methods on HttpContent but placed them in the controller for the purpose of this example.

Upvotes: 3

Related Questions