Send byte array to server - c#

I have an image object that I need to save on the server. I convert it into an array of bytes, and then serialize it into JSON with my optional data. But the server can not successfully convert it and it returns an error message to me:
{
"Message": "Cannot convert object of type 'System.String' to type 'System.Byte[]'",
"StackTrace": " at System.Web.Script.Serialization.ObjectConverter.ConvertObjectToTypeInternal(Object o, Type type, JavaScriptSerializer serializer, Boolean throwOnError, Object& convertedObject) at System.Web.Script.Serialization.ObjectConverter.AssignToPropertyOrField(Object propertyValue, Object o, String memberName, JavaScriptSerializer serializer, Boolean throwOnError) at System.Web.Script.Serialization.ObjectConverter.ConvertDictionaryToObject(IDictionary`2 dictionary, Type type, JavaScriptSerializer serializer, Boolean throwOnError, Object& convertedObject) at System.Web.Script.Serialization.ObjectConverter.ConvertObjectToTypeInternal(Object o, Type type, JavaScriptSerializer serializer, Boolean throwOnError, Object& convertedObject) at System.Web.Script.Services.WebServiceMethodData.StrongTypeParameters(IDictionary`2 rawParams) at System.Web.Script.Services.RestHandler.InvokeMethod(HttpContext context, WebServiceMethodData methodData, IDictionary`2 rawParams) at System.Web.Script.Services.RestHandler.ExecuteWebServiceCall(HttpContext context, WebServiceMethodData methodData)",
"ExceptionType": "System.InvalidOperationException"
}
My Json Data which i send:
{
"articleData": {
"ArticleNumber": "002",
"ArticlePhoto": "/9j/4QBwRXhpZgAATU0AKgAAAAgABIdpAAQAAAABAAAAPgESAAQAAAABAAAAAAEAAAQAAAABAAAC0AEBAAQAAAABAAAFAAAAAAAAA6ACAAMAAAABAWgAAKADAAMAAAABAoAAAJIIAAQAAAABAAAAAAAAAAD/4AAQSkZJRgABAQAAAQABAAD/2wBDABQODxIPDRQSEBIXFRQYHjIhHhwcHj0sLiQySUBMS0dARkVQWnNiUFVtVkVGZIhlbXd7gYKBTmCNl4x9lnN+gXz/2wBDARUXFx4aHjshITt8U0ZTfHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHz/wAARCAKAAWgDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDjKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAoqWigCKipaKAIqKlooAioqWigCKipaKAIqKlooAioqWigCKipaKAIqKlooAioqWigCKipaKAIqKlooAioqWigCKipaKAIqKlooAioqWigCKipaKAIqKlooAioqWigCKipaKAIqKlooAioqWigCKipaKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAND7HF/tfnS/Yov9r86npcVndjIBZQ/wC1+dKLGI/3vzqcVIBxRdgVfsEOP4vzo+wQ/wC1+dWiOKXFF2BT+wQ/7X50v2CH/a/OrYFLii7AqjToD/e/OnjTbfH8X51YWnr0ouwKy6Xbnrv/AO+q6KDwjpkkCORNllBPz/8A1qyVrs7T/jzi/wBwfyqkxGKvg/SyOk//AH3/APWpf+EO0v0n/wC/n/1q3V+7S5piMH/hDtL9J/8Av5/9amnwfpYHSfr/AM9P/rV0Hamsfl/EUAYQ8H6Wc/6/r/z0/wDrUv8Awh2l/wDTf/v5/wDWrdT+L606mM5yfwjpkcRZfOz/AL//ANaqf/CNWHmbf3uMf366m6/1B+orNP8ArR9KBFVfCOmFQcTf99//AFqcPB+ln/nv/wB/P/rVtxn5BTh1oAwj4P0v/pt/38/+tTT4Q0zPHnf99/8A1q6A9aaaQGB/wiOmek3/AH3/APWoPhLSx/z2/wC+/wD61b1NAz7UgML/AIRLTPSb/vv/AOtVHUvDljatGIhL8wOctn+ldZnNZmsgFo8+hpO9tBxeupy50i2H9/8A76pG0i2HZ8f71a2xSOlKYkPVRWdp9zTmj2MU6Xbdg/8A31TTpkHYN/31W15Ef9wUfZ4v7go5Z9w5o9jD/s6H0b/vqm/YIfRv++q3fs8X/PMU020P/PMUcs+4c0exhmwhHZv++qb9ih9G/Ots20X9wUR2sJfmMYxTtLuHNHsYn2OD0b8629J8O2N5Ful83OM8Pis6eNRcSBRgA8AV03h7i2x/s/1qop31Jk01oiL/AIRHTP8Apt/33/8AWpP+ER03/pt/33W9SE1oZnPP4U01WAHm8/7dP/4RLTf+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RZCND+1G/wCeS/nR/aj/APPMfnWfRRZAXTqDE/6sfnSrqTL/AMsx+dUaKOVDuaS6w6jHlL+dQyX7SSh9gBHvVOilyoLsvDUn/uD86P7Tf/nmPzqjRTshF8ao4/5Zj86KoUUWQBRRRTAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAP//Z"
},
"sessionId": "d98b2c41-373a-40af-ac3b-874198e22a08"
}
My Request provider:
public class JsonProvider : IJsonProvider
{
private const string JsonContentType = "application/json";
public async Task<TResult> MakeApiCall<TResult,TData>(string url, HttpMethod method, TData data)
where TResult : class
{
using (var httpClient = new HttpClient())
{
using (var request = new HttpRequestMessage(method, url))
{
if (method != HttpMethod.Get)
{
var json = await Task.Run(() => JsonConvert.SerializeObject(data))
.ConfigureAwait(false);
request.Content = new StringContent(json, Encoding.UTF8, JsonContentType);
}
HttpResponseMessage response = await httpClient.SendAsync(request)
.ConfigureAwait(false);
var stringSerialized = await response.Content.ReadAsStringAsync()
.ConfigureAwait(false);
return await Task.Run(() => JsonConvert.DeserializeObject<TResult>(serialize))
.ConfigureAwait(false);
}
}
}
}
Request Objects:
public class SessionRequest
{
[JsonProperty("sessionId")] public string SessionId { get; set; }
}
public class UploadArticlePhotoRequest : SessionRequest
{
[JsonProperty("articleData")] public PhotoRequest ArticleData { get; set; }
}
public class PhotoRequest
{
[JsonProperty("ArticleNumber")] public string ArticleNumber { get; set; }
[JsonProperty("ArticlePhoto")] public byte[] ArticlePhoto { get; set; }
}
Can the problem in the format of conversion or encoding? Is it a client application or server problem?

Can the problem in the format of conversion or encoding? Is
Read the error message. It is clear. "Cannot convert object of type 'System.String' to type 'System.Byte[]'".
Is it a client application or server problem?
Well, obviously - gibven it is a .NET level error - the error happens on the server. Now, this may be bad data sent, but generally that would be seen as a server level error.
You basically made up a TData and it is not compatible with the data sent.
Happens - lack of reading details. That ALSO leads to horrific code like this:
return await Task.Run(() => JsonConvert.DeserializeObject(serialize))
.ConfigureAwait(false);
Just skip the Task.run and deserialize sync. See, there is no async method for that - with good reason - and you do not gain aynthign with Task.RUn, all you do is make sure 2 threads wait, not one. Antipattern from a lack of reading details and thinking things through. There is no way JsonConvert should be async to start (it is CPU bound, not IO bound) and you force the use of a separate task for it, while the original one waits.

Related

C# how to return key/value json response without using dynamic?

I am working on an Azure Function app and want to have a bunch of methods that return a simple, strongly typed response which serializes to json in a simple way without using OkObjectResult due to it having too many extra properties that I don't need.
Example of desired output, where "Value" can become a complex type serialized to json:
{
FooBar : Value
}
This is pretty easily achieved by using 'dynamic' keyword.
[Function("CreateFooBar")]
public async Task<dynamic> CreateFooBar([HttpTrigger(AuthorizationLevel.Anonymous, "post")]
HttpRequestData req,
FunctionContext executionContext)
{
return new
{
FooBar = "Value"
}
}
However, I don't want to have dynamic everywhere in my code.
How can I make the below code actually work so it serializes using a key/value style mechanism? The JsonSerialization and ISerialization doesn't seem to provide an interface for this?
public class OkResultWithValue
{
public OkResultWithValue(string key,object value)
{
_key= key;
}
private string _key;
public object Value { get; set ; }
}
[Function("CreateFooBar")]
public async Task<OkResultWithValue> CreateFooBar([HttpTrigger(AuthorizationLevel.Anonymous, "post")]
HttpRequestData req,
FunctionContext executionContext)
{
object value = DoSomeThing();
return new OkResultWithValue("FooBar",value)
}
Now I can have all my Azure Functions return a strongly typed OkResultWithValue like this:
You can achieve the same with object instead:
[Function("CreateFooBar")]
public async Task<object> CreateFooBar([HttpTrigger(AuthorizationLevel.Anonymous, "post")]
HttpRequestData req,
FunctionContext executionContext)
{
return new
{
FooBar = "Value"
}
}

FormatException: Cannot deserialize a 'Guid' from BsonType 'ObjectId'

I have been going crazy this last days.
I'm trying to use string Guids as _id's in my MongoDb, with the latest version of the driver. I stumbled with this tutorial, which shed me some light...
Storing GUIDs as strings in MongoDB with C#
But I am getting this error: FormatException: Cannot deserialize a 'Guid' from BsonType 'ObjectId'.
MongoDB.Bson.Serialization.Serializers.GuidSerializer.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
MongoDB.Bson.Serialization.Serializers.SerializerBase<TValue>.MongoDB.Bson.Serialization.IBsonSerializer.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize(IBsonSerializer serializer, BsonDeserializationContext context)
MongoDB.Bson.Serialization.BsonClassMapSerializer<TClass>.DeserializeMemberValue(BsonDeserializationContext context, BsonMemberMap memberMap)
The stack trace:
at MongoDB.Bson.Serialization.BsonClassMapSerializer`1.DeserializeMemberValue(BsonDeserializationContext context, BsonMemberMap memberMap)
at MongoDB.Bson.Serialization.BsonClassMapSerializer`1.DeserializeClass(BsonDeserializationContext context)
at MongoDB.Bson.Serialization.BsonClassMapSerializer`1.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize[TValue](IBsonSerializer`1 serializer, BsonDeserializationContext context)
at MongoDB.Driver.Core.Operations.CursorBatchDeserializationHelper.DeserializeBatch[TDocument](RawBsonArray batch, IBsonSerializer`1 documentSerializer, MessageEncoderSettings messageEncoderSettings)
at MongoDB.Driver.Core.Operations.FindCommandOperation`1.CreateFirstCursorBatch(BsonDocument cursorDocument)
at MongoDB.Driver.Core.Operations.FindCommandOperation`1.CreateCursor(IChannelSourceHandle channelSource, BsonDocument commandResult)
at MongoDB.Driver.Core.Operations.FindCommandOperation`1.Execute(RetryableReadContext context, CancellationToken cancellationToken)
at MongoDB.Driver.Core.Operations.FindOperation`1.Execute(RetryableReadContext context, CancellationToken cancellationToken)
at MongoDB.Driver.Core.Operations.FindOperation`1.Execute(IReadBinding binding, CancellationToken cancellationToken)
at MongoDB.Driver.OperationExecutor.ExecuteReadOperation[TResult](IReadBinding binding, IReadOperation`1 operation, CancellationToken cancellationToken)
at MongoDB.Driver.MongoCollectionImpl`1.ExecuteReadOperation[TResult](IClientSessionHandle session, IReadOperation`1 operation, ReadPreference readPreference, CancellationToken cancellationToken)
at MongoDB.Driver.MongoCollectionImpl`1.ExecuteReadOperation[TResult](IClientSessionHandle session, IReadOperation`1 operation, CancellationToken cancellationToken)
at MongoDB.Driver.MongoCollectionImpl`1.FindSync[TProjection](IClientSessionHandle session, FilterDefinition`1 filter, FindOptions`2 options, CancellationToken cancellationToken)
at MongoDB.Driver.MongoCollectionImpl`1.<>c__DisplayClass45_0`1.<FindSync>b__0(IClientSessionHandle session)
at MongoDB.Driver.MongoCollectionImpl`1.UsingImplicitSession[TResult](Func`2 func, CancellationToken cancellationToken)
at MongoDB.Driver.MongoCollectionImpl`1.FindSync[TProjection](FilterDefinition`1 filter, FindOptions`2 options, CancellationToken cancellationToken)
at MongoDB.Driver.FindFluent`2.ToCursor(CancellationToken cancellationToken)
at MongoDB.Driver.Core.Operations.AsyncCursorSourceEnumerableAdapter`1.GetEnumerator()
at System.Collections.Generic.LargeArrayBuilder`1.AddRange(IEnumerable`1 items)
at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable`1 source)
at System.Linq.SystemCore_EnumerableDebugView`1.get_Items()
I've scoured the Internet in search of an answer.
I DO NOT WANT TO USE POCO's DECORATION, OR RETURN BsonDocuments. Already went this route:
BsonDefaults.GuidRepresentationMode = GuidRepresentationMode.V3;
BsonSerializer.RegisterSerializer<Guid>(new GuidSerializer(GuidRepresentation.Standard));
and didn't work. Also did the convention thing...
public class GuidAsStringRepresentationConvention : ConventionBase, IMemberMapConvention
{
public void Apply(BsonMemberMap memberMap)
{
if (memberMap.MemberType == typeof(Guid))
memberMap.SetSerializer(new GuidSerializer(BsonType.String));
else if (memberMap.MemberType == typeof(Guid?))
memberMap.SetSerializer(new NullableSerializer<Guid>(new GuidSerializer(BsonType.String)));
}
}
Didn't work either...
This is my code:
public class TestClass
{
public Guid Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
}
This gets called BEFORE the Db connection:
if (!BsonClassMap.IsClassMapRegistered(typeof(TestClass)))
{
BsonClassMap.RegisterClassMap<TestClass>(cm =>
{
cm.MapIdMember(m => m.Id).SetOrder(0);
cm.MapMember(m => m.Name).SetOrder(1);
cm.MapMember(m => m.IsActive).SetOrder(2);
});
}
var conn = configuration.GetConnectionString("MongoDb");
var name = MongoUrl.Create(conn).DatabaseName;
var client = new MongoClient(conn);
_db = client.GetDatabase(name);
after that, I try to get the records, after I initialize the collection in the constructor...
public async Task<IEnumerable<TestClass>> ReadAllAsync(CancellationToken cancellationToken = default)
{
var filter = Builders<TestClass>.Filter.Empty;
var items = await _collection.Find<TestClass>(filter).ToListAsync(cancellationToken: cancellationToken);
return items;
}
And of course, I initialize the serializer on "ConfigureServices" in the Startup.cs
BsonSerializer.RegisterSerializer(new GuidSerializer(BsonType.String));
Last, the BSON document with the string GUID (or UUID):
{
"_id" : "c2ea54fc-3942-4ad5-8315-9e96cc5de034",
"name" : "I'm Going Crazy",
"isActive" : true
}
If anyone can shed some light, I would appreciate it a lot. Thanks!!!!
[UPDATE]
I did this:
var col = _db.GetCollection<BsonDocument>("TestCollection");
var list = col.Find(FilterDefinition<BsonDocument>.Empty).ToList();
...and I can see the string GUIDs, everything loads perfectly. It's just NOT PARSING correctly. AND I DON'T KNOW WHY. And I refuse to parse this document manually!!!! That's what the driver is supposed to be doing!
[UPDATE 2]
Decided to decorate the property with:
[BsonId]
[BsonRepresentation(MongoDB.Bson.BsonType.String)]
public Guid Id { get; set; }
Didn't work either...
If you want to keep using Guids natively (rather than treating them as strings), change the serializer you are registering.
Remove:
BsonSerializer.RegisterSerializer(new GuidSerializer(BsonType.String));
And replace it with:
BsonSerializer.RegisterSerializer(new GuidSerializer(GuidRepresentation.Standard));
BsonDefaults.GuidRepresentationMode = GuidRepresentationMode.V3;
Yes, the second line (at time of writing), is an obsolete method, but for now it's the only way to do it. It's an open bug with the c# driver.
There does seem to be an issue here that needs to be fixed.
In the long run we encourage everyone to use the new V3 GuidRepresentationMode, and in fact when using V3 mode this bug does not appear to happen. I added the following line of code as the first line of main:
BsonDefaults.GuidRepresentationMode = GuidRepresentationMode.V3;
We still need to figure out how to get your code to work in V2 mode, but if you are willing to use V3 mode you could have an immediate workaround.
Apparently, the GUIDs I was using were not valid GUIDs. I generated them using an online generator.
I generated new ones on another website, and voilá. Everyting worked.

A collection to save the Actions with type parameter - Cannot convert IEnumerable<dynamic> to IEnumerable<MyEntity>

In the following class for Asp.Net http middleware, there is a method with type parameter (ExportResult<T>(...)) and a dictionary (Exports) to store the method with different type parameters.
public class ExportMiddleware : IMiddleware
{
public Dictionary<string, Func<IEnumerable<dynamic>, string, DataSourceLoadOptionsBase, HttpContext, Task>> Exports =>
new Dictionary<string, Func<IEnumerable<dynamic>, string, DataSourceLoadOptionsBase, HttpContext, Task>>();
public ExportMiddleware()
{
Exports.Add("download1", (IEnumerable<dynamic> source, string format, DataSourceLoadOptionsBase dataOptions, HttpContext context) =>
ExportResult<MyEntity>(source, format, dataOptions, context)); // Error
// Cannot convert IEnumerable<dynamic> to IEnumerable<MyEntity>
}
private async Task ExportResult<T>(IEnumerable<T> source, string format, DataSourceLoadOptionsBase dataOptions, HttpContext context)
{
// ....
// report.DataSource = loadedData.data.Cast<T>();
// ....
}
// Consume the dictionary
public Task InvokeAsync(HttpContext context, RequestDelegate next)
{
// ....
var path = context.Request.Path.ToString();
if (Exports.TryGetValue(path, out var func))
return func(source, format, options, context);
return next(context);
}
How to resolve the error of Cannot convert IEnumerable<dynamic> to IEnumerable<MyEntity> on source?
Is there a way not using dynamic? (there is no class type parameter)
If your code knows that source will be an IEnumerable<MyEntity>, then cast it as such:
Exports.Add("download1", (IEnumerable<dynamic> source, string format, DataSourceLoadOptionsBase dataOptions, HttpContext context) =>
ExportResult((IEnumerable<MyEntity>)source, format, dataOptions, context));
If you want to use the calling pattern in your example, you can move the cast into your Export helper:
private async Task ExportResult<T>(IEnumerable<dynamic> dynamicSource, string format, DataSourceLoadOptionsBase dataOptions, HttpContext context)
{
var source = (IEnumerable<T>)dynamicSource;
If the source is actually a different type of IEnumerable<>, but you happen to know that all the items in it will be of type T, use the LINQ Cast method instead:
private async Task ExportResult<T>(IEnumerable<dynamic> dynamicSource, string format, DataSourceLoadOptionsBase dataOptions, HttpContext context)
{
var source = dynamicSource.Cast<T>();
In any of these cases, you might want to re-think whether dynamic is really what you want. Since IEnumerable<> is covariant, IEnumerable<object> would work just as well in all the code you've shared.

Web API modify incoming payload in formatter

All,
I am trying to modify the payload of incoming object via the web API. Currently I'm using a custom formatter which inherits from JsonMediaTypeFormatter and overrides the relevant methods.
Looks like this:
public override async Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger,
CancellationToken cancellationToken)
{
object obj = await base.ReadFromStreamAsync(type, readStream, content, formatterLogger, cancellationToken);
TrySetEventNo(obj, GetEventNo());
return obj;
}
private void TrySetEventNo(object content, long eventNo)
{
if (content is EventModelBase)
{
EventModelBase eventBase = (EventModelBase)content;
eventBase.EventNo = eventNo;
}
}
I'm using this to track every object that comes through the API.
Before all of this happens, I have a MessageHandler which is creating an event number and adding it to Request.Properties.
Trying to get the event number in the formatter which was created previously in the MessageHandler is proving difficult. Access HttpContext.Current.Items["MS_HttpRequestMessage"].Properties seems to be a different request as it does not contain the event number.
I've two questions:
Am I doing this the correctly or is there a better way?
If I am taking the correct approach, how to I get the correct Request to extract the event number?
Thanks
I've found a solution, instead of attempting to do this inside a formatter I'm now using an ActionFilterAttribute.
overriding OnActionExecuting(HttpActionContext actionContext) and enumerating action actionContext.ActionArguments.
The complete solution looks like so:
public class SetModelEventNumberActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
foreach (KeyValuePair<string, object> actionArgument in actionContext.ActionArguments)
{
TrySetEventNo(actionArgument.Value, GetEventNo(actionContext));
}
base.OnActionExecuting(actionContext);
}
private void TrySetEventNo(object content, long eventNo)
{
if (content is EventPivotRequestMessageBase)
{
EventPivotRequestMessageBase eventBase = (EventPivotRequestMessageBase)content;
eventBase.EventNo = eventNo;
}
}
private long GetEventNo(HttpActionContext actionContext)
{
long eventNo = (long)actionContext.Request.Properties[Constant.EVENT_ID];
return eventNo;
}
}

How do you get to the original message text in a Microsoft Bot Framework LuisIntent method

I'm trying to access the complete original text from within a method marked as a LuisIntent within a LuisDialog.
The documentation shows these methods as taking two arguments:
IDialogContext context, LuisResult result
Neither of which publicly exposes the original text of the message. The context object does contain the message but in a private property (context.data.message.text) which is not accessible.
Is there a way to access this in the context, or can it be passed into the dialog constructor?
With the new version of Bot Framework (1.0.2) the LuisResult object now has a Query parameter that contains the original query sent to LUIS.
You can override the MessageReceived(...) function of the LuisDialog keep the fields of the message that you need as member variables and access those fields in your intent handlers. Below I modified the SimpleAlarmDialog to show how you can access 'message.Text' in one of the intent handlers:
[LuisModel("c413b2ef-382c-45bd-8ff0-f76d60e2a821", "6d0966209c6e4f6b835ce34492f3e6d9")]
[Serializable]
public class SimpleAlarmDialog : LuisDialog<object>
{
private readonly Dictionary<string, Alarm> alarmByWhat = new Dictionary<string, Alarm>();
[Serializable]
public class PartialMessage
{
public string Text { set; get; }
}
private PartialMessage message;
protected override async Task MessageReceived(IDialogContext context, IAwaitable<Message> item)
{
var msg = await item;
this.message = new PartialMessage { Text = msg.Text };
await base.MessageReceived(context, item);
}
[LuisIntent("builtin.intent.alarm.delete_alarm")]
public async Task DeleteAlarm(IDialogContext context, LuisResult result)
{
await context.PostAsync($"echo: {message.Text}");
Alarm alarm;
if (TryFindAlarm(result, out alarm))
{
this.alarmByWhat.Remove(alarm.What);
await context.PostAsync($"alarm {alarm} deleted");
}
else
{
await context.PostAsync("did not find alarm");
}
context.Wait(MessageReceived);
}
}
If you break into the method, you can see in the quick watch that the context object has a non-public property through to context.data.mesage.Text (note the misspelling of "mesage"). Since the property is non-public, you could cheat by using reflection to get at it (see GetInstanceField in How to get the value of private field in C#?)
Microsoft.Bot.Builder.Dialogs.Internals.JObjectBotData data = GetInstanceField(typeof (Microsoft.Bot.Builder.Dialogs.Internals.DialogContext), context, "data") as Microsoft.Bot.Builder.Dialogs.Internals.JObjectBotData;
Microsoft.Bot.Connector.Message originalMessage = GetInstanceField(typeof(Microsoft.Bot.Builder.Dialogs.Internals.JObjectBotData), data, "mesage") as Microsoft.Bot.Connector.Message;
string originalMessageText = originalMessage.Text;
You could do it like this by using the Query property of the LuisResult,
[LuisIntent(intentName: "someIntentName")]
private async Task Eligibility(IDialogContext context, LuisResult result)
{
await context.PostAsync($"The original text is: {result.Query}");
context.Wait(MessageReceivedAsync);
}

Categories