Post Web Api发布错误->;值不能为null。参数名称:uriString

Post Web Api发布错误->;值不能为null。参数名称:uriString,post,asp.net-web-api,asp.net-web-api-routing,Post,Asp.net Web Api,Asp.net Web Api Routing,我对Web Api比较陌生,发布Person对象时遇到问题。如果我在debug中运行,我会发现我的uriString从未设置过,我不明白为什么。正因为如此,我在Fiddler中获得了所有尝试发布的“400错误请求”错误 当涉及到后期行动时,我尝试复制其他人的做法。我发现的每个示例都使用存储库将此人添加到数据库中。但是,我没有存储库,而是使用NHibernate Save方法来实现此功能。下面是域类、按代码文件映射、WebApiConfig和PersonController public clas

我对Web Api比较陌生,发布Person对象时遇到问题。如果我在debug中运行,我会发现我的uriString从未设置过,我不明白为什么。正因为如此,我在Fiddler中获得了所有尝试发布的“400错误请求”错误

当涉及到后期行动时,我尝试复制其他人的做法。我发现的每个示例都使用存储库将此人添加到数据库中。但是,我没有存储库,而是使用NHibernate Save方法来实现此功能。下面是域类、按代码文件映射、WebApiConfig和PersonController

public class Person
{
    public Person() { }

    [Required]
    public virtual string Initials { get; set; }
    public virtual string FirstName { get; set; }
    public virtual char MiddleInitial { get; set; }
    public virtual string LastName { get; set; }
}

public class PersonMap : ClassMapping<Person>
{
    public PersonMap() 
    {
        Table("PERSON");
        Lazy(false);

        Id(x => x.Initials, map => map.Column("INITIALS"));

        Property(x => x.FirstName, map => map.Column("FIRST_NAME"));
        Property(x => x.MiddleInitial, map => map.Column("MID_INITIAL"));
        Property(x => x.LastName, map => map.Column("LAST_NAME"));  
    }
}



public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        var json = config.Formatters.JsonFormatter;
        json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
        config.Formatters.Remove(config.Formatters.XmlFormatter);

        config.Services.Replace(typeof(IHttpActionSelector), new HybridActionSelector());



        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}/{action}/{actionid}/{subaction}/{subactionid}",
            defaults: new { id = RouteParameter.Optional, action = RouteParameter.Optional,
                            actionid = RouteParameter.Optional, subaction = RouteParameter.Optional, subactionid = RouteParameter.Optional }
        );


        config.BindParameter( typeof( IPrincipal ), new ApiPrincipalModelBinder() );

        // Uncomment the following line of code to enable query support for actions with an IQueryable or IQueryable<T> return type.
        // To avoid processing unexpected or malicious queries, use the validation settings on QueryableAttribute to validate incoming queries.
        // For more information, visit http://go.microsoft.com/fwlink/?LinkId=279712.
        //config.EnableQuerySupport();

        // To disable tracing in your application, please comment out or remove the following line of code
        // For more information, refer to: http://www.asp.net/web-api
        config.EnableSystemDiagnosticsTracing();
    }
}



public class PersonsController : ApiController
{
    private readonly ISessionFactory _sessionFactory;

    public PersonsController (ISessionFactory sessionFactory)
    {
        _sessionFactory = sessionFactory;
    }

    // POST api/persons
    [HttpPost]
    public HttpResponseMessage Post(Person person)
    {
        var session = _sessionFactory.GetCurrentSession();

        using (var tx = session.BeginTransaction())
        {
            try
            {
                if (!ModelState.IsValid)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
                }

                var result = session.Save(person);
                var response = Request.CreateResponse<Person>(HttpStatusCode.Created, person);

                string uriString = Url.Route("DefaultApi", new { id = person.Initials });
                response.Headers.Location = new Uri(uriString); 


                tx.Commit();
                return response;
            }
            catch (Exception)
            {
                tx.Rollback();
            }
            throw new HttpResponseException(HttpStatusCode.BadRequest);
        }
    }
}
以及使用单独的routeconfig

config.Routes.MapHttpRoute(
            name: "PostApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional
        } );

而且没有运气

解决方案

通过使用下面的代码行,我能够使这篇文章起作用。我不完全确定这是否是正确的方法,因此,如果有人知道不同,请分享。否则,我很乐意使用这种方法

response.Headers.Location = new Uri(this.Request.RequestUri.AbsoluteUri + "/" + person.Initials);

问题似乎在这里:

string uriString = Url.Route("DefaultApi", new { id = person.Initials });

您只传递
id
,而需要传递其他参数,如控制器等。

您可以通过以下方式构造URL:

string uriString = Url.Action("ActionName", "ControllerName", new { Id = person.Initials });

我尝试过用空字符串表示除控制器之外的所有剩余参数。在那里,我将其设置为“个人”。我仍然得到一个空URI字符串,但是我的web api中不存在.Url.Action。你能告诉我这是为什么吗?
string uriString = Url.Route("DefaultApi", new { id = person.Initials });
string uriString = Url.Action("ActionName", "ControllerName", new { Id = person.Initials });