AsProjection() throwing exception for async query - ravendb

In a simple test scenario which can be setup using the following:
public class TestObj
{
public string Id { get; set; }
public string Name { get; set; }
}
public class Summary
{
public string MyId { get; set; }
public string MyName { get; set; }
}
public class TestObjs_Summary : AbstractIndexCreationTask<TestObj, Summary>
{
public TestObjs_Summary()
{
Map = docs => docs.Select(d => new { MyId = d.Id, MyName = d.Name });
Store(x => x.MyId, FieldStorage.Yes);
Store(x => x.MyName, FieldStorage.Yes);
}
}
static IDocumentStore Setup()
{
var store = new DocumentStore() { Url="http://localhost:8080" };
store.Initialize();
IndexCreation.CreateIndexes(MethodInfo.GetCurrentMethod().DeclaringType.Assembly, store);
using (var session = store.OpenSession())
{
session.Store(new TestObj { Name = "Doc1" });
session.Store(new TestObj { Name = "Doc2" });
session.SaveChanges();
}
return store;
}
I can run a simple synchronous query against the index and get the expected results (2 rows output of type Summary):
using (var session = store.OpenSession())
{
var q = session.Query<Summary>("TestObjs/Summary").AsProjection<Summary>();
Dump("Sync:", q.ToList());
}
However, if I try the same thing using an asynchronous query:
using (var session = store.OpenAsyncSession())
{
var q = session.Query<Summary>("TestObjs/Summary").AsProjection<Summary>();
q.ToListAsync().ContinueWith(t => Dump("Async:", t.Result));
}
I get an InvalidCastException:
InnerException: System.InvalidCastException
Message=Unable to cast object of type 'TestObj' to type 'Summary'.
Source=Raven.Client.Lightweight
StackTrace:
at Raven.Client.Document.InMemoryDocumentSessionOperations.ConvertToEntity[T](String id, RavenJObject documentFound, RavenJObject metadata) in c:\Builds\RavenDB-Unstable\Raven.Client.Lightweight\Document\InMemoryDocumentSessionOperations.cs:line 416
at Raven.Client.Document.InMemoryDocumentSessionOperations.TrackEntity[T](String key, RavenJObject document, RavenJObject metadata) in c:\Builds\RavenDB-Unstable\Raven.Client.Lightweight\Document\InMemoryDocumentSessionOperations.cs:line 340
at Raven.Client.Document.SessionOperations.QueryOperation.Deserialize[T](RavenJObject result) in c:\Builds\RavenDB-Unstable\Raven.Client.Lightweight\Document\SessionOperations\QueryOperation.cs:line 130
...
I suspect this is a bug, but as a RavenDB newbie, I first wanted to rule out the possibility I have screwed something up here. Can anyone see why this code would be failing?
(Note: this was run on Build 721 and on 701 and both produce the same results)
Thanks for any assistance you can provide.

It looks like a bug. I don't see anything wrong in your code. I suggest you create an issue here: http://issues.hibernatingrhinos.com

Related

How do you manage the visible input fields accepted in an API HttpPost request?

In my API I have a Create method in my controller that accepts all of the models fields, but in the method I'm excluding the ID field since on a create it's generated. But in Swagger it's showing the following.
Is there a way for it not to show the following part?
"id": 0
Is a viewmodel how I should go about this?
I tried the following, but can't get it to work.
public class PartVM
{
public string Name { get; set; }
}
public interface IPartService
{
Task<Part> CreatePart(PartVM part);
Task<IEnumerable<Part>> GetParts();
Task<Part> GetPart(int partId);
}
public class PartService : IPartService
{
private readonly AppDbContext _appDbContext;
public PartService(AppDbContext appDbContext)
{
_appDbContext = appDbContext;
}
public async Task<Part> CreatePart(PartVM part)
{
var _part = new Part()
{
Name = part.Name
};
var result = await _appDbContext.Parts.AddAsync(_part);
await _appDbContext.SaveChangesAsync();
return result.Entity;
}
}
Here's my controller.
[Route("api/[controller]")]
[ApiController]
public class PartsController : ControllerBase
{
private readonly IPartService _partService;
public PartsController(IPartService partService)
{
_partService = partService;
}
[HttpPost]
public async Task<ActionResult<Part>> CreatePart(PartVM part)
{
try
{
if (part == null)
return BadRequest();
var _part = new Part()
{
Name = part.Name
};
var createdPart = await _partService.CreatePart(_part);
return CreatedAtAction(nameof(GetPart),
new { id = createdPart.Id}, createdPart);
}
catch (Exception /*ex*/)
{
return StatusCode(StatusCodes.Status500InternalServerError, "Error creating new record in the database");
}
}
I'm getting a build error saying "CS1503 Argument 1: cannot convert from 'MusicManager.Shared.Part' to 'MusicManager.Server.Data.ViewModels.PartVM'".
It's refering to "_part" in this line "var createdPart = await _partService.CreatePart(_part);".
Any help is appreciated, thank you!
you have a CreatePart method which receives a PartVM model, but you are sending a Part Model to it
change your method to this :
public async Task<Part> CreatePart(Part part)
{
var result = await _appDbContext.Parts.AddAsync(_part);
await _appDbContext.SaveChangesAsync();
return result.Entity;
}

Xunit Parameterize Selenium By Type

I have asked several basic questions related to this in the past and got great answers that explained several issues. I think i'm now in a position to ask the correct question now that I'm more aware of how Xunit works!
I am trying to parametrize several tests in C# using visual studio. I need each parameter to be displayed as an individual test that can be ran in isolation if required (I know there is a test collection runner and a separate test runner). The test collection runner is my issue.
I know that Xunit requires the parameters to be serialized in order for them to be picked up by the test collection runner. I also know that it by default can easily serialize basic data types like string, bool, int etc.
I have tried various approaches to do this with mixed results. My issue is trying to parameterize the Selenium type 'By'. I can't seem to be able to serialize this. I've tried to trick Xunit for example by using a dictionary List<string, By> and trying to serialize the in the dictionary (no luck!)
Here is the cleanest code I have come across that is simple and elegant for what i'm trying to do, but again I can't serialize the 'By' type. I have played around with changing the static property from bool to By and it returns only 1 test for all params, so it's not being serialized
public class ParamTest1
{
static string test3 = "TestXYZ";
public static TheoryData<int, bool, string, string> DataForTest1 = new TheoryData<int, bool, string, string>
{
{ 1, true, "First", test3 },
{ 2, false, "Second", test3},
{ 3, true, "Third", test3}
};
[Theory(DisplayName = "My First Test"), MemberData(nameof(DataForTest1))]
public void Test1(int valA, bool valB, string valC, string valD)
{
Assert.True(valB);
}
}
Which gives me
I am aware this particular code isn't invoking the IXunitSerializable
So here is an another working example of what I need but I just can't get it to work with the 'By' Type
public class ValidateTestCase : IXunitSerializable
{
public Guid Coupon { get; set; }
public bool IsValid { get; set; }
public void Serialize(IXunitSerializationInfo info)
{
info.AddValue(nameof(Coupon), Coupon.ToString());
}
public void Deserialize(IXunitSerializationInfo info) { }
}
public class Testing
{
public static IEnumerable<object[]> ValidateTestCases
{
get
{
yield return new object[] { new ValidateTestCase { Coupon = Guid.Parse("73e4d185-70cf-4ce4-bc3f-187b7a40e167"), IsValid = false } };
yield return new object[] { new ValidateTestCase { Coupon = Guid.Parse("93b983fb-5b6a-4845-a769-db41900b7df9"), IsValid = false } };
yield return new object[] { new ValidateTestCase { Coupon = Guid.Parse("99c03283-33cb-4e56-a010-c2bc0758ad27"), IsValid = false } };
yield return new object[] { new ValidateTestCase { Coupon = Guid.Parse("16a7fe80-3111-44b0-9ebf-c7159bea637d"), IsValid = false } };
yield return new object[] { new ValidateTestCase { Coupon = Guid.Parse("8b38b4aa-d70f-4ce7-8992-8a60936c5c58"), IsValid = false } };
yield return new object[] { new ValidateTestCase { Coupon = Guid.Parse("abc60aa0-a33b-4057-8f99-5cdceda35c70"), IsValid = true } };
}
}
[Theory(DisplayName = "CouponService should validate coupons")]
[MemberData(nameof(ValidateTestCases))]
public void MyCouponService_Validates(ValidateTestCase vtc)
{
Assert.Equal(vtc.IsValid, true);
}
}
And finally for anyone wondering what the 'By' type is I am referring to it's :
[![enter image description here][2]][2]
Here it is in the debugger so you can see what's going on inside:
[![enter image description here][3]][3]
I know there's a lot going on in there but if anyone has any ideas or suggestions it would be great!
To summarize, I can't parameterize the Selenium 'data type' By.
[2]: https://i.stack.imgur.com/XcLcn.png
[3]: https://i.stack.imgur.com/T9so1.png
Serializing Class
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;
using OpenQA.Selenium;
using Xunit.Abstractions;
namespace XUnitTestProject1
{
public class ParameterizedHook
{
public By p1 { get; set; }
public By p2 { get; set; }
public string assertion { get; set; }
}
public class TheoryWrapper<T> : IXunitSerializable
{
public TheoryWrapper(string label, T #object)
{
Name = label;
Object = #object;
}
public TheoryWrapper()
{
}
public string Name { get; set; }
public T Object { get; set; }
public void Deserialize(IXunitSerializationInfo info)
{
Name = info.GetValue<string>("Label");
Object = JsonConvert.DeserializeObject<T>(info.GetValue<string>("objValue"));
}
public void Serialize(IXunitSerializationInfo info)
{
info.AddValue("Label", Name, typeof(string));
var json = JsonConvert.SerializeObject(Object);
info.AddValue("objValue", json);
}
public override string ToString()
{
return Name;
}
}
}
Working Test
public static IEnumerable<object[]> ComplexTheoryData
{
get
{
return new List<object[]>
{
new object[] {0, new TheoryWrapper<ParameterizedHook>("Pass0", new ParameterizedHook { p1 = nav_hold.pip_builder.dash_expand_pip_builder_menu, p2 = nav_hold.pip_builder.dash_project_stages, assertion = "WORK STAGE" })},
new object[] {0, new TheoryWrapper<ParameterizedHook>("Pass0", new ParameterizedHook { p1 = nav_hold.pip_builder.dash_expand_pip_builder_menu, p2 = nav_hold.pip_builder.dash_project_stages, assertion = "WORK STAGES" })},
//new object[] {0, new TheoryWrapper<ParameterizedHook>("Pass0", new ParameterizedHook { TestData = b.login })},
//new object[] {1, new TheoryWrapper<ParameterizedHook>("Pass1", new ParameterizedHook { TestData = b.password })}
};
}
}
[SkippableTheory]
[Trait("xUnit", "ForTestRunner")]
[MemberData(nameof(ComplexTheoryData))]
public void Test_Navigation(int id, TheoryWrapper<ParameterizedHook> test)
{
nav_met.NavMethodTest(test.Object.p1, test.Object.p2);
By page_title = By.Id("ctl00_lblPageTitle");
Assert.True(nav_met.VerifyText(page_title, test.Object.assertion));
}

FluentValidation failure not returning BadRequest

I have wired up FluentValidation as per instructions, and when debuging test I can see that model is invalid based on the test setup, but exception is not thrown, but rather method on the controller is being executed. This is on 3.1 with EndPoint routing enabled. Is there anything else one needs to do to get this to work and throw. What happens is that validation obviously runs; it shows as ModelState invalid and correct InstallmentId is invalid, but it keeps processing in Controller instead of throwing exception.
services.AddMvc(
options =>
{
options.EnableEndpointRouting = true;
//// options.Filters.Add<ExceptionFilter>();
//// options.Filters.Add<CustomerRequestFilter>();
})
.AddFluentValidation(
config =>
{
config.RegisterValidatorsFromAssemblyContaining<Startup>();
})
Command and Validator
public class ProcessManualPayment
{
public class Command
: CustomerRequest<Result?>
{
public Guid PaymentPlanId { get; set; }
public Guid InstallmentId { get; set; }
public Guid PaymentCardId { get; set; }
}
public class Validator : AbstractValidator<Command>
{
public Validator()
{
this.RuleFor(x => x.CustomerId)
.IsValidGuid();
this.RuleFor(x => x.PaymentPlanId)
.IsValidGuid();
this.RuleFor(x => x.InstallmentId)
.IsValidGuid();
this.RuleFor(x => x.PaymentCardId)
.IsValidGuid();
}
}
Controller
[Authorize]
[HttpPost]
[Route("payments")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> ProcessManualPayment(
[FromBody]
ProcessManualPayment.Command command)
{
Test
[Fact]
public async Task When_Command_Has_Invalid_Payload_Should_Fail()
{
var client = this.factory.CreateClient();
// Arrange
var validCmd = new ProcessManualPayment.Command()
{
CustomerId = Guid.NewGuid(),
PaymentPlanId = Guid.NewGuid(),
InstallmentId = Guid.NewGuid(),
PaymentCardId = Guid.NewGuid(),
};
var validCmdJson = JsonConvert.SerializeObject(validCmd, Formatting.None);
var jObject = JObject.Parse(validCmdJson);
jObject["installmentId"] = "asdf";
var payload = jObject.ToString(Formatting.None);
// Act
var content = new StringContent(payload, Encoding.UTF8, MediaTypeNames.Application.Json);
var response = await client.PostAsync(MakePaymentUrl, content);
var returned = await response.Content.ReadAsStringAsync();
response.StatusCode.ShouldBe(HttpStatusCode.BadRequest);
}
[Fact]
public async Task When_Payload_Is_Null_Should_Fail()
{
// Arrange
var client = this.factory.CreateClient();
// Act
var response = await client.PostAsJsonAsync(MakePaymentUrl, null);
// Assert
response.StatusCode.ShouldBe(HttpStatusCode.BadRequest);
}
GuidValidator
public class GuidValidator : PropertyValidator
{
public GuidValidator()
: base("'{PropertyName}' value {AttemptedValue} is not a valid Guid.")
{
}
protected override bool IsValid(PropertyValidatorContext context)
{
context.MessageFormatter.AppendArgument("AttemptedValue", context.PropertyValue ?? "'null'");
if (context.PropertyValue == null)
{
return false;
}
Guid.TryParse(context.PropertyValue.ToString(), out var value);
return IsValid(value);
}
private static bool IsValid(Guid? value) =>
value.HasValue
&& !value.Equals(Guid.Empty);
}
Mystery solved, I was missing [ApiController] attribute on the controller.

XML Serialization - Required attribute

I have a class that should represent a controller's action parameter and I'd like its properties to be "required" (meaning, you get a status code 400 or something in case it's passed as null). I managed to get it done using System.ComponentModel.DataAnnotations, but the ErrorMessage that I pass to the constructor of the Required attribute is never shown.
[XmlRoot(ElementName = "root")]
public class Request
{
[XmlElement(ElementName = "prop")]
[Required(ErrorMessage = "The property is required.")]
public string Property { get; set; }
[XmlElement(ElementName = "another")]
[Required(ErrorMessage = "The property is required.")]
public string Another { get; set; }
}
Action:
[HttpPost]
public IActionResult Post([FromBody] Request value)
{
return Ok(value); //ignore this, it's just for testing purposes...
}
However, if I don't pass the Property value, I get a 400 that doesn't contain the ErrorMessage I passed earlier. Am I missing something here?
<ValidationProblemDetails xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Title>One or more validation errors occurred.</Title>
<Status>400</Status>
</ValidationProblemDetails>
My Startup has Xml formatters added to it:
services.AddMvc(options =>
{
options.RespectBrowserAcceptHeader = true;
options.InputFormatters.Insert(0, new XmlSerializerInputFormatter(options));
options.OutputFormatters.Insert(0, new XmlSerializerOutputFormatter());
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
The body of the request looks like this, and it doesn't have "Property":
<root>
<another>Test</another>
<!-- Property "Property" is missing here -->
</root>
Kudos to Code Rethinked for the huge help - Customizing automatic HTTP 400 error response in ASP.NET Core Web APIs.
An approach that I managed to figure out eventually includes the use of services.Configure in my Startup.ConfigureServices method.
services.Configure<ApiBehaviorOptions>(options =>
{
options.InvalidModelStateResponseFactory = context =>
{
return new OkObjectResult(new CustomResponse(someStatusCode, context))
{
ContentTypes = { "application/xml" }
};
};
});
So, I made a class named CustomResponse that holds the status code I want to retrieve and all the validation errors (including the ones where my Required property was not passed to the API).
[XmlRoot(ElementName = "rcemsTrxSubReqAck")]
public class CustomResponse
{
[XmlElement(ElementName = "Status")]
public string Status { get; set; }
[XmlArray(ElementName = "Errors"), XmlArrayItem(ElementName = "Error")]
public string[] Errors { get; set; }
public CustomResponse(int status, ActionContext context)
{
Status = status;
Errors = ConstructErrorMessages(context);
}
private string[] ConstructErrorMessages(ActionContext context)
{
if (context == null)
{
return null;
}
string[] arr = new string[context.ModelState.ErrorCount];
int i = 0;
foreach (var keyModelStatePair in context.ModelState)
{
var key = keyModelStatePair.Key;
var errors = keyModelStatePair.Value.Errors;
if (errors != null && errors.Count > 0)
{
if (errors.Count == 1)
{
var errorMessage = GetErrorMessage(errors[0]);
arr[i] = $"{key}: {errorMessage}";
}
else
{
var errorMessages = new string[errors.Count];
for (var j = 0; j < errors.Count; j++)
{
errorMessages[j] = GetErrorMessage(errors[j]);
}
arr[i] = $"{key}: {errorMessages.ToString()}";
}
i++;
}
}
return arr;
}
private string GetErrorMessage(ModelError error)
{
return string.IsNullOrEmpty(error.ErrorMessage) ? "The input was not valid." : error.ErrorMessage;
}
}

RavenDB static index on dictionary

I have an application that uses documents, that contain list of attributes in a dictionary, for some reason we need to use a static index and query/filter over these attributes.
A prototype looks like this:
class Program
{
static void Main(string[] args)
{
IDocumentStore store = new DocumentStore() { DefaultDatabase = "Test", Url = "http://localhost:8081" };
store.Initialize();
IndexCreation.CreateIndexes(typeof(Program).Assembly, store);
using (var session = store.OpenSession())
{
session.Store(new Document { Id = "1", Name = "doc_name", Attributes = new Dictionary<string, object> { { "Type", "1" }, { "Status", "Active" } } });
session.SaveChanges();
}
using (var session = store.OpenSession())
{
// works
var l1 = session.Query<Document, Documents_Index>().Where(a => a.Attributes["Type"] == "1").ToList();
// not working
var l2 = session.Query<Document, Documents_Index>().Where(a => a.Attributes["Status"] == "Active").ToList();
}
}
}
public class Documents_Index : AbstractIndexCreationTask<Document>
{
public Documents_Index()
{
Map = docs => docs.Select(a =>
new
{
a.Name,
a.Attributes,
Attributes_Type = a.Attributes["Type"]
});
}
}
[Serializable]
public class Document
{
public string Id { get; set; }
public string Name { get; set; }
public Dictionary<string, object> Attributes { get; set; }
}
But since I need to query using any arbitrary Attribute name/value this index does solve our problem. Actually the list of attributes is known at run-time (so we tried modifying the Map expression to inject any number of attribute names, but so far we weren't successful). Is there a way how to define the index in some dynamic fashion?
You need to write it like:
public class Documents_Index : AbstractIndexCreationTask<Document>
{
public Documents_Index()
{
Map = docs => docs.Select(a =>
new
{
a.Name,
_ = a.Attributes.Select(x=>CreateField("Attributes_"+x.Key, x.Value),
});
}
}