【问题标题】:how to save an object using .net webapi如何使用.net webapi保存对象
【发布时间】:2012-07-27 17:10:20
【问题描述】:

我在 .net 中创建了 WebAPI(我的第一个)。使用这个 api 从数据库中获取对象、查询数据库等对我来说很容易。没什么新意

但我想知道如何使用这个 webapi 保存一个对象?

我有一个与我的 webapi 通信的客户端应用程序(平板电脑、手机、PC)。从我的应用程序中可以保存用户新闻。现在我需要将它保存在数据库中。我使用 Azure SQL。现在如何将这个对象传递给 API 以便我可以保存它?

对于我的应用程序,我使用 C#/XAML 对于我的 WebAPI,我使用 .NET

我正在使用此代码:

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

但我不知道如何发送对象?我应该序列化它吗?如果是,如何通过邮寄方式发送。

// 更新

我已经构建了这个

        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);

但在我的 API 中,变量为空

这是来自我的 api 的代码

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

“测试”变量为空。 我做错了什么?

// 更新 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);
        }

路由配置

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 }
        );
    }
}

在你的所有答案之后,我创建了这个,但我的 api 中的参数仍然为空。哪里错了?

【问题讨论】:

    标签: c# windows-8 windows-runtime asp.net-web-api azure-sql-database


    【解决方案1】:

    WebAPI真的擅长解析发送给它的数据并将其转换为 .NET 对象。

    我不习惯使用带有 WebAPI 的 C# 客户端,但我会尝试以下方法:

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

    注意:您需要为此使用System.Net.Http(来自同名程序集)以及System.Net.Http.Formatting(也来自同名程序集)。

    【讨论】:

    • 没有像 PostAsJsonAsync 这样的方法。我发现只有 PostAsync。我不能在那里设置我的对象。第二个参数是 HttpContent。这和你想给我看的一样吗?
    • Fixus,您使用的是 RC 版本的 ASP.NET MVC 4 还是旧版本的 Web API?
    • Im using VS RC 2012 and Ive 使用 .Net Framework 4.5 创建了项目
    • 确保您已添加对我提到的两个程序集的引用 - 以及 using 子句。但是你也可以使用 PostAsync,只是有点冗长:client.PostAsync("uri", yourobject, new JsonMediaTypeFormatter());
    • 我注意到他用 windows-8 和 windows-runtime 标记了他的帖子,这意味着他正在编写一个“Windows Store”(以前的“Metro”)应用程序,尽管他没有明确说明这一点。如果是这样,那就可以解释为什么他没有这些方法——据我所知,.NET 4.5 的 WinRT 版本不包括定义 System.Net.Http.Formatting.dllHttpClientExtensions 类(通常在 System.Net.Http.Formatting.dll 中) @(并且 VS 不允许您从主 .NET 类库中添加对库的引用)。
    【解决方案2】:

    HttpRequestMessage 类有一个名为Content 的属性,它是HttpContent(一个抽象类)的类型。您可以在那里设置请求正文。例如,您可以在此处设置 JSON 内容,然后将其发送到 API:

    HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uri) { 
    
        Content = new StringContent("{'Name':'Foo', 'Surname':'Bar'}")
    };
    

    您还可以使用格式化功能并将您的 CLR 对象提供给 ObjectContent 并将序列化委托给格式化程序。

    这里有很多关于 HttpClient 和 Web API 的示例:http://blogs.msdn.com/b/henrikn/archive/2012/07/20/asp-net-web-api-sample-on-codeplex.aspx

    【讨论】:

    • 谢谢。现在我知道如何设置内容,但发送后我得到空值。我已经更新了我的代码。如果你看看它会很酷:)
    • @Fixus 尝试使用FromBody 属性:public void Post([FromBody]string test)
    • 当我添加这个方法时不会被调用。我的意思是我的 API 中的 Post 方法。当我删除它时,它被调用但测试变量为空
    【解决方案3】:

    假设您的 Web API 控制器上有一个支持 POST 操作的操作方法,类似于:

    [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)
                }
            );
        }
    }
    

    您可以使用 HttpClient 将您的对象序列化为 JSON 并将内容发布到您的控制器方法:

    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;
        }
    }
    

    我还建议您查看Creating a Web API that Supports CRUD Operations,它涵盖了您所描述的场景,特别是创建资源部分。

    【讨论】:

    • 感谢您的建议。我ve updated my post. Could you look on it ? I think Im 关闭:)
    • 我已经更新了我的帖子并添加了路由配置。有小费吗 ? :)
    • 阅读您的评论后,我检查了路由。我已将 webapi 中函数名称的参数从“test”更改为“id”。现在在我的 api 中,变量获取值“insert”,其中此 post 操作的 url 是 // POST sd/Localization/insert public void Post(String id)。我仍然没有得到我想要的值,但至少这不是空的。任何想法我做错了什么?
    • 使用 PostAsJsonAsync 方法而不是在请求消息中显式构建内容,并将您的复杂类型作为参数添加到控制器方法中。模型绑定不会将请求内容转换为复杂类型(您在 JSON 中定义的类型)。您应该使用要发送的属性定义一个“用户”类,并将其用作控制器方法中的参数,以便模型绑定将 JSON 有效负载转换为反序列化的对象表示。
    • 我在 HttpClient 中没有 PostAsJsonAsync 方法。我只有 PostAsync,我无法在其中设置类型。我写了关于那个。也许是因为我是在 Windows 8 中编写的
    【解决方案4】:

    我想我找到了解决方案,这就是为什么我将其发布为答案而不是评论,以便以后的任何讨论都可以分组。

    如果我这样发送请求

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

    我可以从我的 webapi 中获取它

    await Request.Content.ReadAsStringAsync();
    

    IMO 这不是完美的解决方案,但至少我正在追踪。我看到函数定义中的参数只有在 URL 中才能获取,即使我发送 POST 请求也是如此。

    当我使用比字符串更复杂的对象时,这个解决方案可能也会起作用(我还没有检查过)。

    某人的任何想法。您认为这是一个好的解决方案吗?

    【讨论】:

    • 您是否有理由希望以字符串而不是强类型对象表示形式发送和接收数据?
    • 我没有可以设置类型的 PostAsJsonAsync。我有 PostAsync,我只能将消息设置为 HttpContent 类
    • 这对于您的问题可能真的很晚,但我今天找到了它并挣扎了好几个小时。您无法将对象发布到您的 webapi 的原因是因为您的模型没有默认构造函数(在 web api 端),一旦您添加了一个空的默认构造函数,它就可以正常工作。我会为后代发布答案
    【解决方案5】:

    我希望这就是你要找的。​​p>

    我创建了一个通用的 Post 可以接受任何对象并发布它
    客户端

    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;
       }
    }
    

    对此的调用将像

    一样简单
    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;
    }
    

    此外,如果您的用例需要,您可以在发布后使​​用 ReadAsStringAsync() 读取对象。


    服务器端

    // 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);
        }
    

    【讨论】:

      【解决方案6】:

      我不熟悉 HttpClient(我相信它是 .NET 4.5),但 WebAPI 背后的概念是使用标准的 RESTful 结构。如果要通过 WebAPI 插入对象,则需要向服务发送 POST 请求。您应该将对象的内容放入请求的 BODY 中。

      【讨论】:

      • 如何设置我的请求正文?我找不到任何样品:(
      【解决方案7】:

      为您的 webapi 模型人员添加空构造函数。这将为您节省我浪费在试图弄清楚为什么我的对象为空的所有时间。 序列化(我想是反序列化)需要默认构造函数。

      【讨论】:

        【解决方案8】:

        这是我的方式。它成功了。我希望它有帮助 首先:是你必须拥有的所有库。你可以从 nuget 下载

        使用 Newtonsoft.Json;使用 Newtonsoft.Json.Linq;

        客户:

        HttpClient client = new HttpClient();
        
        //this is url to your API server.in local.You must change when u pushlish on real host
        Uri uri = new Uri("http://localhost/");
        client.BaseAddress = uri;
        
        //declared a JArray to save object 
        JArray listvideoFromUser = new JArray();
        
        //sample is video object
        VideoModels newvideo = new VideoModels();
        
        //set info to new object..id/name...etc.
        newvideo._videoId = txtID.Text.Trim();
        
        //add to jArray
        listvideoFromUser.Add(JsonConvert.SerializeObject(newvideo));
        
        //Request to server
        //"api/Video/AddNewVideo" is router of API .you must change with your router
        HttpResponseMessage response =client.PostAsJsonAsync("api/Video/AddNewVideo", listvideoFromUser).Result;
        if (response.IsSuccessStatusCode){
            //show status process
             txtstatus.Text=response.StatusCode.ToString();
        }
        else{
            //show status process
            txtstatus.Text=response.StatusCode.ToString();
        }  
        

        服务器端:

        [Route("api/Video/AddNewVideo")]
        [System.Web.Http.HttpPost]
        public HttpResponseMessage AddNewVideo(JArray listvideoFromUser){
            if (listvideoFromUser.Count > 0){
                //DeserializeObject: that object you sent from client to server side. 
                //Note:VideoModels is class object same as model of client side
                VideoModels video = JsonConvert.DeserializeObject<VideoModels>(listvideoFromUser[0].ToString());
        
                //that is just method to save database
                Datacommons.AddNewVideo(video);
        
                //show status for client
                HttpResponseMessage response = new HttpResponseMessage { StatusCode = HttpStatusCode.Created };
                return response;
            }
            else{
                HttpResponseMessage response = new HttpResponseMessage { StatusCode = HttpStatusCode.InternalServerError };
                return response;
            }
        }
        

        全部完成!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-11-05
          • 1970-01-01
          • 1970-01-01
          • 2013-07-22
          • 2012-05-16
          • 1970-01-01
          • 2013-03-10
          相关资源
          最近更新 更多