Fix the ArgumentNull exception (#537)

* Fix the ArgumentNull exception



Co-authored-by: Sander Molenkamp <a.molenkamp@gmail.com>
Co-authored-by: Ryan Nowak <nowakra@gmail.com>
This commit is contained in:
vinayada1 2021-01-12 09:16:58 -08:00 committed by GitHub
parent 4a193ec1ac
commit ac7e20e070
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 147 additions and 6 deletions

View File

@ -69,15 +69,26 @@ namespace Dapr.AspNetCore
bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, message);
return;
}
var obj = await this.thunk(daprClient, this.storeName, key);
bindingContext.Result = ModelBindingResult.Success(obj);
bindingContext.ValidationState.Add(bindingContext.Result.Model, new ValidationStateEntry()
// When the state isn't found in the state store:
// - If the StateEntryModelBinder is associated with a value of type StateEntry<T>, then the above call returns an object of type
// StateEntry<T> which is non-null, but StateEntry<T>.Value is null
// - If the StateEntryModelBinder is associated with a value of type T, then the above call returns a null value.
if (obj == null)
{
// Don't do validation since the data came from a trusted source.
SuppressValidation = true,
});
bindingContext.Result = ModelBindingResult.Failed();
}
else
{
bindingContext.Result = ModelBindingResult.Success(obj);
bindingContext.ValidationState.Add(bindingContext.Result.Model, new ValidationStateEntry()
{
// Don't do validation since the data came from a trusted source.
SuppressValidation = true,
});
}
}
private static async Task<object> GetStateEntryAsync<T>(DaprClient daprClient, string storeName, string key)

View File

@ -5,6 +5,7 @@
namespace Dapr.AspNetCore.IntegrationTest.App
{
using System;
using System.Threading.Tasks;
using Dapr;
using Dapr.Client;
@ -53,5 +54,18 @@ namespace Dapr.AspNetCore.IntegrationTest.App
// To simulate an action where there's no Dapr attribute, yet MVC still checks the list of available model binder providers.
return user;
}
[HttpGet("controllerwithoutstateentry/{widget}")]
public ActionResult<Widget> Get([FromState("testStore")] Widget widget)
{
return widget;
}
[HttpGet("controllerwithstateentry/{widgetStateEntry}")]
public ActionResult<Widget> Get([FromState("testStore")] StateEntry<Widget> widgetStateEntry)
{
return widgetStateEntry.Value;
}
}
}

View File

@ -5,10 +5,12 @@
namespace Dapr.AspNetCore.IntegrationTest
{
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Dapr.AspNetCore.IntegrationTest.App;
using FluentAssertions;
using Newtonsoft.Json;
using Xunit;
public class ControllerIntegrationTest
@ -32,6 +34,43 @@ namespace Dapr.AspNetCore.IntegrationTest
}
}
[Fact]
public async Task ModelBinder_GetFromStateEntryWithKeyPresentInStateStore_ReturnsStateValue()
{
using (var factory = new AppWebApplicationFactory())
{
var httpClient = factory.CreateClient();
var daprClient = factory.DaprClient;
var widget = new Widget() { Size = "small", Count = 17, };
await daprClient.SaveStateAsync("testStore", "test", widget);
var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/controllerwithoutstateentry/test");
var response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsStringAsync();
var responseWidget = JsonConvert.DeserializeObject<Widget>(responseContent);
responseWidget.Size.Should().Be(widget.Size);
responseWidget.Count.Should().Be(widget.Count);
}
}
[Fact]
public async Task ModelBinder_GetFromStateEntryWithKeyNotInStateStore_ReturnsNull()
{
using (var factory = new AppWebApplicationFactory())
{
var httpClient = factory.CreateClient();
var daprClient = factory.DaprClient;
var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/controllerwithoutstateentry/test");
var response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsStringAsync();
var responseWidget = JsonConvert.DeserializeObject<Widget>(responseContent);
Assert.Null(responseWidget);
}
}
[Fact]
public async Task ModelBinder_CanBindFromState_WithStateEntry()
{
@ -70,6 +109,43 @@ namespace Dapr.AspNetCore.IntegrationTest
}
}
[Fact]
public async Task ModelBinder_GetFromStateEntryWithStateEntry_WithKeyPresentInStateStore()
{
using (var factory = new AppWebApplicationFactory())
{
var httpClient = factory.CreateClient();
var daprClient = factory.DaprClient;
var widget = new Widget() { Size = "small", Count = 17, };
await daprClient.SaveStateAsync("testStore", "test", widget);
var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/controllerwithstateentry/test");
var response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsStringAsync();
var responseWidget = JsonConvert.DeserializeObject<Widget>(responseContent);
responseWidget.Size.Should().Be(widget.Size);
responseWidget.Count.Should().Be(widget.Count);
}
}
[Fact]
public async Task ModelBinder_GetFromStateEntryWithStateEntry_WithKeyNotInStateStore()
{
using (var factory = new AppWebApplicationFactory())
{
var httpClient = factory.CreateClient();
var daprClient = factory.DaprClient;
var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/controllerwithstateentry/test");
var response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsStringAsync();
var responseWidget = JsonConvert.DeserializeObject<Widget>(responseContent);
Assert.Null(responseWidget);
}
}
[Fact]
public async Task ModelBinder_CanGetOutOfTheWayWhenTheresNoBinding()
{

View File

@ -90,6 +90,46 @@ namespace Dapr.AspNetCore.Test
context.ValidationState[context.Result.Model].SuppressValidation.Should().BeTrue();
}
[Fact]
public async Task BindAsync_ReturnsNullForNonExistentStateEntry()
{
var binder = new StateEntryModelBinder("testStore", "id", isStateEntry: false, typeof(Widget));
// Configure Client
var httpClient = new TestHttpClient();
var context = CreateContext(CreateServices(httpClient));
context.HttpContext.Request.RouteValues["id"] = "test";
var task = binder.BindModelAsync(context);
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
await SendResponseWithState<string>(null, entry);
await task;
context.ModelState.IsValid.Should().BeTrue();
context.Result.IsModelSet.Should().BeFalse();
context.Result.Should().Be(ModelBindingResult.Failed());
}
[Fact]
public async Task BindAsync_WithStateEntry_ForNonExistentStateEntry()
{
var binder = new StateEntryModelBinder("testStore", "id", isStateEntry: true, typeof(Widget));
// Configure Client
var httpClient = new TestHttpClient();
var context = CreateContext(CreateServices(httpClient));
context.HttpContext.Request.RouteValues["id"] = "test";
var task = binder.BindModelAsync(context);
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
await SendResponseWithState<string>(null, entry);
await task;
context.ModelState.IsValid.Should().BeTrue();
context.Result.IsModelSet.Should().BeTrue();
((StateEntry<Widget>)context.Result.Model).Value.Should().BeNull();
}
private static ModelBindingContext CreateContext(IServiceProvider services)
{
return new DefaultModelBindingContext()