how to save an object using .net webapi

20,012

Solution 1

I think I found the solution thats why I'm posting this as answer not comment so any later discussion could be grouped.

If I send request like this

using(HttpClient client = new HttpClient()) {
    await client.PostAsync(uri, new StringContent("my own string");
}

Than I can get it in my webapi from

await Request.Content.ReadAsStringAsync();

IMO this is not perfect solution but at least I'm on trace. I see that params from function definitione I can get only if they are in URL even when I send a POST request.

Probably this solution also will work (i didn't check it yet) when I use more complex objects then String.

ANy thoughts from someone. Do you think that this is good solution ?

Solution 2

WebAPI is really good at parsing data sent to it and converting it to .NET objects.

I am not used to using a C# client with WebAPI, but I'd try the following:

var client = new HttpClient();
client.PostAsJsonAsync<YourObjectType>("uri", yourObject);

Note: You need to use System.Net.Http (from assembly with the same name) as well as System.Net.Http.Formatting (also from assembly with the same name) for this.

Solution 3

The HttpRequestMessage class has a property named Content which is type of HttpContent (an abstract class). You can set the request body there. For example, you can set the JSON content there and then send it to the API:

HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uri) { 

    Content = new StringContent("{'Name':'Foo', 'Surname':'Bar'}")
};

You can also use the formatting feature and supply your CLR object to ObjectContent and delegate the serialization to the Formatter.

There are lots of samples on HttpClient and Web API here: http://blogs.msdn.com/b/henrikn/archive/2012/07/20/asp-net-web-api-sample-on-codeplex.aspx

Solution 4

Assuming you have an action method on your web API controller that supports a POST operation that is similiar to:

[HttpPost()]
public HttpResponseMessage Post(YourObjectType value)
{
    try
    {

        var result      = this.Repository.Add(value);

        var response = this.Request.CreateResponse<YourObjectType>(HttpStatusCode.Created, result);

        if (result != null)
        {
            var uriString               = this.Url.Route(null, new { id = result.Id });
            response.Headers.Location   = new Uri(this.Request.RequestUri, new Uri(uriString, UriKind.Relative));
        }

        return response;
    }
    catch (ArgumentNullException argumentNullException)
    {
        throw new HttpResponseException(
            new HttpResponseMessage(HttpStatusCode.BadRequest)
            {
                ReasonPhrase    = argumentNullException.Message.Replace(Environment.NewLine, String.Empty)
            }
        );
    }
}

You can use the HttpClient to serialize your object to JSON and POST the content to you controller method:

using (var client = new HttpClient())
{
    client.BaseAddress  = baseAddress;
    client.Timeout      = timeout;

    using (var response = client.PostAsJsonAsync<YourObjectType>("controller_name", yourObject).Result)
    {
        if (!response.IsSuccessStatusCode)
        {
            // throw an appropriate exception
        }

        result  = response.Content.ReadAsAsync<YourObjectType>().Result;
    }
}

I would also recommend taking a look at Creating a Web API that Supports CRUD Operations, which covers the scenarios you are describing, specifically the Creating a Resource section.

Solution 5

I hope this would be what you are looking for.

I created a generic Post that will accept any object and post it
Client Side

public async Task<HttpResponseMessage> Post<T>(string requestUri, T newObject) where T : class
{
  using (var client = new HttpClient())
  {
     client.BaseAddress = this.HttpClientAddress;
     client.DefaultRequestHeaders.Accept.Clear();
     client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
     var content = JsonConvert.SerializeObject(newObject, this.JsonSerializerSettings);
     var clientAsync = await client.PostAsync(requestUri, new StringContent(content, Encoding.UTF8, "application/json"));
     clientAsync.EnsureSuccessStatusCode();

     return clientAsync;
   }
}

the call to this will be as simple as

public async Task<int> PostPerson(Models.Person person)
{
  //call to the generic post 
  var response = await this.Post("People", person);

  //get the new id from Uri api/People/6 <-- this is generated in the response after successful post
  var st =  response.Headers.Location.Segments[3];

  //do whatever you want with the id
  return response.IsSuccessStatusCode ? JsonConvert.DeserializeObject<int>(st) : 0;
}

Also, you can read the object after the post using ReadAsStringAsync() if your usecase requires so.


Server Side

// POST: api/People
  public IHttpActionResult Post(Models.Person personDto)
    {

        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        var person = new Entities.Person
                     {
                             FirstName = personDto.FirstName,
                             LastName = personDto.LastName,
                             DateOfBirth = personDto.DateOfBirth,
                             PreferedLanguage = personDto.PreferedLanguage

                     };
        _db.Persons.Add(person);
        _db.SaveChanges();
        return CreatedAtRoute("DefaultApi", new { id = person.Id }, personDto);
    }
Share:
20,012
Fixus
Author by

Fixus

I`m good at what I am doing

Updated on July 09, 2022

Comments

  • Fixus
    Fixus almost 2 years

    I've create WebAPI in .net (my first). Using this api to get object from db, query db etc is easy for me. Nothing new

    But I'm wondering how to save an object using this webapi ?

    I have a clinet application (tablet, phone, PC) that communicates with my webapi. From my application there is an possibility to save a user news. Now I need to save it in db. I use Azure SQL. Now how can I pass this object to API so I can save it ?

    For my application I use C#/XAML For my WebAPI I use .NET

    I'm tring with this code:

    HttpClient httpClient = new HttpClient();
            String u = this.apiUrl + "sd/Localization/insert";
            Uri uri = new Uri(u);
            HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, uri);
    

    But I don't know how to send object ? Should I serialize it ? If yes how to send it via post.

    // UPDATE

    I've constructed this

            HttpClient httpClient = new HttpClient();
            String u = this.apiUrl + "sd/Localization/insert";
            Uri uri = new Uri(u);
            HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, uri);
            httpRequestMessage.Content = new StringContent("{'Name':'Foo', 'Surname':'Bar'}");
            await httpClient.PostAsync(uri, httpRequestMessage.Content);
    

    But in my API the variable is null

    This is code from my api

        // POST sd/Localization/insert
        public void Post(string test)
        {
            Console.WriteLine(test);
        }
    

    The "test" variable is null. What am I doing wrong ?

    // UPDATE 2

            using (HttpClient httpClient = new HttpClient())
            {
                String u = this.apiUrl + "sd/Localization/insert";
                Uri uri = new Uri(u);
                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uri)
                {
                    Method = HttpMethod.Post,
                    Content = new StringContent("my own test string")
                };
    
                await httpClient.PostAsync(uri, request.Content);
            }
    

    Routing config

    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
            routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "sd/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
    
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
    

    after all your answers I've created this but still I get null on param in my api. Where is the mistake ?