- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
目前我正在尝试创建一个基于 asp.net core 2.0 的 web api,我想创建一个嵌套路由。如果是放置请求,它会在路由中发送一部分信息,在正文中发送另一部分信息。
需要调用的 url 是
https://localhost/api/v1/master/42/details
如果我们想在我们的 master 42 下面创建一个新的细节,我希望在 master 的 id 从路由中出来时在 body 中发送细节的数据。
curl -X POST --header 'Content-Type: application/json' \
--header 'Accept: application/json' \
-d '{ \
"name": "My detail name", \
"description": "Just some kind of information" \
}' 'https://localhost/api/v1/master/42/details'
请求的输出响应将是
{
"name": "My detail name",
"description": "Just some kind of information",
"masterId": 42,
"id": 47
}
和响应 header 中的位置 url,如
{
"location": "https://localhost/api/v1/master/42/details/47
}
为了让它工作,我创建了这个 Controller :
[Produces("application/json")]
[Route("api/v1/master/{masterId:int}/details")]
public class MasterController : Controller
{
[HttpPost]
[Produces(typeof(DetailsResponse))]
public async Task<IActionResult> Post([FromBody, FromRoute]DetailCreateRequest request)
{
if(!ModelState.IsValid)
return BadRequest(ModelState);
var response = await Do.Process(request);
return CreatedAtAction(nameof(Get), new { id = response.Id }, response);
}
}
它使用这些类:
public class DetailCreateRequest
{
public int MasterId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public class DetailResponse
{
public int Id { get; set; }
public int MasterId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
到目前为止,大部分内容都按预期工作。唯一真正不起作用的是将路由中的 MasterId 合并到来自正文的 DetailCreateRequest
中。
我试图通过这个 Action 调用将这两件事结合起来:
public async Task<IActionResult> Post([FromBody, FromRoute]DetailCreateRequest request)
但是传入对象只有一个 MasterId
为零。如果我更改这两个属性的顺序,那么只会采用路由中的 id,并且忽略正文中的所有值(因此似乎是第一个属性获胜)。
我尝试的另一种方法是此操作调用:
public async Task<IActionResult> Post([FromRoute]int masterId, [FromBody]DetailCreateRequest request)
在第一个位置这看起来没问题,因为现在我在 Controller 操作中有两个值。但我对这种方法的最大问题是模型验证。正如你在上面的代码中看到的,我检查了 ModelState.IsValid
,它是通过 FluentValidation
的一些检查填充的,但是这些检查不能真正完成,因为对象是'由于缺少主 ID 而正确构建。
试图实现这样的东西:
public async Task<IActionResult> Post([FromMultiple(Merge.FromBody, Merge.FromRoute)]DetailCreateRequest request)
如果我们已经有了这样的东西,那就太好了。属性中参数的顺序将给出合并(以及可能的覆盖)发生的顺序。
我已经开始实现此属性并为所需的 IValueProvider
和 IValueProviderFactory
创建框架。但这似乎是相当多的工作。特别是找到所有漂亮的细节,使它能够与我正在使用的 asp.net 核心和其他库的整个管道无缝地工作(比如通过 swashbuckle 招摇过市)。
所以我的问题是,asp.net core 中是否已经存在某种机制来实现这样的合并,或者是否有人知道已经存在的解决方案或关于如何实现这种野兽的好例子。
从Merchezatter得到答案后我研究了如何创建 custom model binder并想出了这个实现:
public class MergeBodyAndValueProviderBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
throw new ArgumentNullException(nameof(bindingContext));
var body = bindingContext.HttpContext.Request.Body;
var type = bindingContext.ModelMetadata.ModelType;
var instance = TryCreateInstanceFromBody(body, type, out bool instanceChanged);
var bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
var setters = type.GetProperties(bindingFlags).Where(property => property.CanWrite);
foreach (var setter in setters)
{
var result = bindingContext.ValueProvider.GetValue(setter.Name);
if (result != ValueProviderResult.None)
{
try
{
var value = Convert.ChangeType(result.FirstValue, setter.PropertyType);
setter.SetMethod.Invoke(instance, new[] { value });
instanceChanged = true;
}
catch
{ }
}
}
if (instanceChanged)
bindingContext.Result = ModelBindingResult.Success(instance);
return Task.CompletedTask;
}
private static object TryCreateInstanceFromBody(Stream body, Type type, out bool instanceChanged)
{
try
{
using (var reader = new StreamReader(body, Encoding.UTF8, false, 1024, true))
{
var data = reader.ReadToEnd();
var instance = JsonConvert.DeserializeObject(data, type);
instanceChanged = true;
return instance;
}
}
catch
{
instanceChanged = false;
return Activator.CreateInstance(type);
}
}
}
它尝试将主体反序列化为所需的对象类型,然后尝试应用来自可用值提供者的更多值。为了让这个模型绑定(bind)器工作,我必须用 ModelBinderAttribute 装饰目标类并将 MasterId 设为内部,这样 swagger 就不会宣布它并且 JsonConvert 不会反序列化它:
[ModelBinder(BinderType = typeof(MergeBodyAndValueProviderBinder))]
public class DetailCreateRequest
{
internal int MasterId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
在我的 Controller 中, Action 方法参数仍然包含 [FromBody]
标志,因为 swagger 使用它来宣布如何调用该方法,但它永远不会被调用,因为我的模型 Binder 具有更高的优先级。
public async Task<IActionResult> Post([FromBody]DetailCreateRequest request)
所以它并不完美,但到目前为止效果很好。
最佳答案
这看起来是个正确的选择:
[HttpPost]
[Produces(typeof(DetailsResponse))]
public async Task<IActionResult> Post([FromRoute]int masterId, [FromBody]DetailCreateRequest request) {
//...
}
但是如果您在域模型验证方面遇到一些问题,请创建不带主 ID 的自定义 Dto 对象。否则,您可以使用自定义模型绑定(bind)器,然后使用来自操作和绑定(bind)上下文的参数。
关于c# - 如何: Parameter binding from multiple sources,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46217544/
我正在尝试设计我的输入:文件。以下 SO 问题让我完成了 95% 的任务。区别在于我使用的是 HTML5 multiple=multiple 属性。 How to style "input file"
我一直在进行一项实验,其中多个调查参与者使用可穿戴技术聆听多首音乐来跟踪多条信息,两个例子是 BPM(心率)和 T(体温)。 目标是衡量每首音乐(以用户反馈为特征)对人类情感的影响。 目前,所有数据都
我使用 jquery 添加/删除输入 我使用append为日期/收入添加多个Tr 我还使用另一个附加来添加多个 td 以获取同一日期 Tr 中的收入 我添加多个日期输入,并在此表中添加多个收入输入 我
在 Android 中,有一种方法可以为项目中的所有模块生成签名的 APK。例如。我有以下项目 Project -- Library Module -- Module 1 -- Modul
我有一个用于网站展示的系统。 展览数据可能来自差异表中的多个数据。 喜欢这个设计: Table [ExhibitionType] used for differentiate category. Ta
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭 8 年前。 Improve
我正在使用 UILocalnotification...收到通知时,当应用程序处于事件模式时我打开 viewcontroller...但是如果同时收到多个通知...我如何打开多个 viewcontro
我遇到的问题是一个策略浏览器游戏,它有 7 种类型的值。问题如下: 我在 $_POST 中获得了 7 个不同的值,包括从索引 unit_1 到索引 unit_7。这 7 个值是 0 到 20 之间的整
这个问题已经有答案了: Search Large Text File for Thousands of strings (3 个回答) 已关闭10 年前。 我想在多个文件上“grep”多个正则表达式。
我经常对如何在我的应用程序中解决这个问题感到矛盾。我使用了很多选项,包括: 一个通用的多选 - 这是我最不喜欢和最很少使用的选项。我发现可用性非常糟糕,一个简单的误点击就会毁了你所有的辛勤工作。 “自
以下是 couchbase 中的示例文档之一。 { "name":"abc", "friends":["a","b","c"], "bestfriends":["x","y","z"] }
我有 4 张 table 。 表组 | ID | NAME | 1 Premium 2 Silver 表用户 | ID | group_id | NAME | 1
我正在开发一个使用第三方服务(Facebook、Google 等)对用户进行身份验证的应用程序。我为每个用户提供一个内部 ID(uuid v4),该 ID 与他们的第 3 方 ID 相关联。现在,我的
我是 bicep 新手,一直在努力实现 Bicep 脚本来部署具有许多主题和订阅的 Azure 服务总线。 我添加的每个主题都有可变数量的订阅(例如,通知主题可能有 3 个订阅,但分析主题可能有 2
我是 bicep 新手,一直在努力实现 Bicep 脚本来部署具有许多主题和订阅的 Azure 服务总线。 我添加的每个主题都有可变数量的订阅(例如,通知主题可能有 3 个订阅,但分析主题可能有 2
我必须创建一个大型数据库。它将保存来自 100 多个设备的数据,并不断更新数据库。每 10 秒,每个设备都会更新数据库中的一行。是为每个设备数据建立一个单独的表还是将数据与设备 ID 放在同一个表中更
我需要在 Activity 开始时显示“正在加载”进度对话框,然后在加载完成后显示一些内容。在我的 onresume 中,我有类似这样的代码: loadThread = true; Thread sh
我有一个 html 表单 当我提交表单时,假设对于 id = 1,数量为 5 或 对于 id = 3,数量为 8。如何在java脚本或jquery中获取这些值并将这些信息提交到服务器?我
我正在创建一个 Mozilla 扩展程序,通过单击“转换按钮”(标签:转换)将网页内容转换为其他语言它的标签被转换为英文,以便单击该按钮(标签:英文)内容被转换为原始形式 我尝试为每个选项卡设置属性“
我正在尝试根据 进行搜索 我通过运行代码从 select 中获取值: for($i=0;$i= '$age_from' AND users.user_age = '$age_from' AND u
我是一名优秀的程序员,十分优秀!