Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/334.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用oData忽略POST中的JSON属性_C#_Entity Framework_Api_Odata - Fatal编程技术网

C# 使用oData忽略POST中的JSON属性

C# 使用oData忽略POST中的JSON属性,c#,entity-framework,api,odata,C#,Entity Framework,Api,Odata,我正在尝试用EntityFramework和ODataV4构建一个API 问题:我需要一些额外的数据,extraProperty,这些数据不在我的数据库中,用于创建一个新的项目,但是如果我在POST调用中将一些数据添加到我的JSON对象中,oData不会将其识别为项目 我使用EntityFrameWork,因此,据我所知,我尝试使用数据注释[NotMapped]或.Ignore(t=>t.extroperty)在我的模型中。但小田似乎忽视了这一点 我从这篇文章中得到的一切,加上这个额外属性,就是

我正在尝试用EntityFramework和ODataV4构建一个API

问题:我需要一些额外的数据,
extraProperty
,这些数据不在我的数据库中,用于创建一个新的
项目
,但是如果我在
POST
调用中将一些数据添加到我的JSON对象中,oData不会将其识别为
项目

我使用EntityFrameWork,因此,据我所知,我尝试使用数据注释
[NotMapped]
.Ignore(t=>t.extroperty)在我的模型中。但小田似乎忽视了这一点

我从这篇文章中得到的一切,加上这个
额外属性
,就是:

不支持非打开类型中的非类型化值

代码 JSON我在我的POST通话中发送:

{
  "name": "John Doe",
  "extraProperty": "Random string"
}
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
    <edmx:DataServices>
        <Schema Namespace="MyApi.Models" xmlns="http://docs.oasis-open.org/odata/ns/edm">
            <EntityType Name="Items">
                <Key>
                    <PropertyRef Name="id" />
                </Key>
                <Property Name="id" Type="Edm.Int32" Nullable="false" />
                <Property Name="name" Type="Edm.String" Nullable="false" />                
            </EntityType>           
        </Schema>
    </edmx:DataServices>
</edmx:Edmx>
$metadata:

{
  "name": "John Doe",
  "extraProperty": "Random string"
}
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
    <edmx:DataServices>
        <Schema Namespace="MyApi.Models" xmlns="http://docs.oasis-open.org/odata/ns/edm">
            <EntityType Name="Items">
                <Key>
                    <PropertyRef Name="id" />
                </Key>
                <Property Name="id" Type="Edm.Int32" Nullable="false" />
                <Property Name="name" Type="Edm.String" Nullable="false" />                
            </EntityType>           
        </Schema>
    </edmx:DataServices>
</edmx:Edmx>
MyModel.cs

namespace MyApi.App_Start
{
    public class OdataConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.MapHttpAttributeRoutes();
            ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
            builder.EntitySet<Items>("Items");
            config.Count().Filter().OrderBy().Expand().Select().MaxTop(null);
            config.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());
        }
    }
}
[Table("Item.Items")]
public partial class Items
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Items(){}

    public int id { get; set; }

    public string name { get; set; }

    [NotMapped] // I already tried this, it's not working
    public string extraProperty{ get; set; }
 }
public partial class MyModel: DbContext
{
    public MyModel()
        : base("name=MyModel")
    {

        Database.SetInitializer<MyModel>(null);
    }

    public virtual DbSet<Items> Items{ get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // I also tried this but not working
        modelBuilder.Entity<Items>()
            .Ignore(e => e.extraProperty);
    }
}
public class ItemsController : ODataController
{
    private MyModeldb = new MyModel();

    // POST: odata/Items 
    public async Task<IHttpActionResult> Post(Items items)
    {
        // items is always null when enterring here
        // and this condition is always triggered
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        // Do some stuff with extraProperty here

        db.Items.Add(items);
        await db.SaveChangesAsync();

        return Created(items);
    }
}
公共部分类MyModel:DbContext
{
公共MyModel()
:base(“name=MyModel”)
{
Database.SetInitializer(null);
}
公共虚拟数据库集项{get;set;}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
//我也试过了,但不起作用
modelBuilder.Entity()
.Ignore(e=>e.extraProperty);
}
}
MyController.cs

namespace MyApi.App_Start
{
    public class OdataConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.MapHttpAttributeRoutes();
            ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
            builder.EntitySet<Items>("Items");
            config.Count().Filter().OrderBy().Expand().Select().MaxTop(null);
            config.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());
        }
    }
}
[Table("Item.Items")]
public partial class Items
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Items(){}

    public int id { get; set; }

    public string name { get; set; }

    [NotMapped] // I already tried this, it's not working
    public string extraProperty{ get; set; }
 }
public partial class MyModel: DbContext
{
    public MyModel()
        : base("name=MyModel")
    {

        Database.SetInitializer<MyModel>(null);
    }

    public virtual DbSet<Items> Items{ get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // I also tried this but not working
        modelBuilder.Entity<Items>()
            .Ignore(e => e.extraProperty);
    }
}
public class ItemsController : ODataController
{
    private MyModeldb = new MyModel();

    // POST: odata/Items 
    public async Task<IHttpActionResult> Post(Items items)
    {
        // items is always null when enterring here
        // and this condition is always triggered
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        // Do some stuff with extraProperty here

        db.Items.Add(items);
        await db.SaveChangesAsync();

        return Created(items);
    }
}
公共类项控制器:ODataController
{
private MyModeldb=new MyModel();
//邮政:odata/Items
公共异步任务发布(项)
{
//在此处输入时,项始终为空
//这种情况总是被触发的
如果(!ModelState.IsValid)
{
返回请求(ModelState);
}
//在这里做一些关于外部属性的事情
db.Items.Add(项目);
等待db.saveChangesSync();
已创建的退货(项目);
}
}
Partial package.config

<package id="EntityFramework" version="6.2.0" targetFramework="net461" />
<package id="Microsoft.Data.Edm" version="5.8.3" targetFramework="net461" />
<package id="Microsoft.AspNet.OData" version="6.1.0" targetFramework="net45" />
<package id="Microsoft.Data.OData" version="5.8.3" targetFramework="net461" />
<package id="Microsoft.OData.Core" version="7.4.1" targetFramework="net45" />
<package id="Microsoft.OData.Edm" version="7.4.1" targetFramework="net45" />

我还想做一个拦截器,在调用post之前清除我的json,但据我所知,Web API OData不支持查询拦截器

如何处理并避免此错误?我真的需要在POST方法中处理
extraProperty
,或者至少在之前处理。

FluentAPI方法可以正常工作(经过多次测试)。 你能提供你的$metadata吗? 请在模型生成器上删除NotMapped属性并添加Ignore,然后重试

或者,您可以在GetEdmModel方法中将此属性添加到IEdmModel:

model.StructuralTypes.First(t => t.ClrType == typeof(Items)).AddProperty(typeof(Items).GetProperty("extraProperty"));

根据您希望使用“额外数据”的目的,对post方法使用输入模型、对数据执行您想要的操作,然后填充适当的EF模型属性不是更简单吗。如果注释和FluentAPI不适合您,这将是最简单的解决方案

i、 e

public分部类ItemsInput
{
公共int id{get;set;}
公共字符串名称{get;set;}
公共字符串外部属性{get;set;}
}
公共异步任务Post(ItemsInput ItemsInput)
{
//除非这是一个有效的错误,否则不应该再触发它
如果(!ModelState.IsValid)
{
返回请求(ModelState);
}
//在这里做一些关于外部属性的事情
//将输入对象转换为json字符串
var itemsInputJson=JsonConvert.serialized对象(itemsInput);
//将json字符串加载到EF模型,这将填充所有兼容的
//属性,忽略不匹配的属性
Items=JsonConvert.DeserializeObject(itemsInputJson);
db.Items.Add(项目);
等待db.saveChangesSync();
已创建的退货(项目);
}

您可以使用AutoMapper将所有内容映射到DTO,然后在控制器中手动应用查询选项

注意:请记住包括

使用自动制版机

使用AutoMapper.QueryableExtensions

公共类ItemDTO
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共字符串CustomProperty{get;set;}
}
公共类项控制器:ApiController
{
MyCustomContext\u context;
公共项控制器(MyCustomContext上下文)
{
_上下文=上下文;
}
公共IEnumerable Get(ODataQueryOptions q)
{
var itemsQuery=_context.Items.AsQueryable();
itemsQuery=q.ApplyTo(itemsQuery,new-ODataQuerySettings())作为IQueryable;
var mapperConfiguration=this.GetMapperConfiguration();
返回itemsQuery.ProjectTo(mapperConfiguration);
}
公共IConfigurationProvider GetMapperConfiguration()
{
返回新的MapperConfiguration(x=>x.CreateMap().FormMember(m=>m.CustomProperty,o=>o.MapFrom(d=>d.Id+“Custom”));
}
}

注意:必须使用
MapFrom
方法进行映射,您不能使用
resolve

项目
类中,删除

public string extraProperty{ get; set; }
并将以下代码留在
MyModel
类中

modelBuilder.Entity<Items>()
            .Ignore(e => e.extraProperty);
modelBuilder.Entity()
.Ignore(e=>e.extraProperty);

[NotMapped]
属性告诉
OData
在序列化和反序列化Items类时忽略
extraProperty
。但是,由于您希望在
ItemsController
POST
请求中使用它,因此在此场景中不能使用
[NotMapped]
属性,因此模型绑定按您的意愿进行。

谢谢您的回答。我再次尝试使用方法、注释和fluentapi,但仍然出现错误。我还将$metadata和OdataConfig.cs添加到我的帖子中。找不到您正在谈论的IED模型的位置。它的生成器位于OdataConfig->Register:)异常消息是一条提示,您应该使用它来处理其他数据。您是否只尝试了modelBuilder.Entity().Ignore(e=>e.extraProperty);没有[NotMapped]注释?另外,您能否在Fiddler中捕获Post请求,并查看原始请求中是否确实发送了项目?@hem,原始很好,我已经尝试了modelBuilder.Entity().Ignore(e=>e.extraProperty);具有