Azure service bus Message deserialize broken in core conversion - serialization

So, I've created a new Azure Functions project v3 and am porting over a subset of functions from v1 that was running on 4.6.2, while retiring the rest as obsolete. Unfortunately in the change from BrokeredMessage to Message due to changing from Microsoft.ServiceBus.Messaging to Microsoft.Azure.ServiceBus the following deserialization method is now failing with:
There was an error deserializing the object of type stream. The input source is not correctly formatted.
The problem is right there in the error, but Im not sure what the correct new approach is, its a bit unclear.
Serialize
public static Message CreateBrokeredMessage(object messageObject)
{
var message = new Message(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(messageObject)))
{
ContentType = "application/json",
Label = messageObject.GetType().Name
};
return message;
}
Deserialize
public static T ParseBrokeredMessage<T>(Message msg)
{
var body = msg.GetBody<Stream>();
var jsonContent = new StreamReader(body, true).ReadToEnd();
T updateMessage = JsonConvert.DeserializeObject<T>(jsonContent);
return updateMessage;
}
Object
var fileuploadmessage = new PlanFileUploadMessage()
{
PlanId = file.Plan_Id.Value,
UploadedAt = uploadTimeStamp,
UploadedBy = uploadUser,
FileHash = uploadedFileName,
FileName = file.Name,
BusinessUnitName = businessUnitName,
UploadedFileId = uploadedFile.Id
};
```

Message.GetBody<T>() is an extension method for messages sent using the legacy Service Bus SDK (WindowsAzure.ServiceBus package) where BrokeredMessage was populated with anything other than Stream. If your sender sends an array of bytes as you've showed, you should access it using Message.Body property.
In case your message is sent as a BrokeredMessage, the receiving code will need to select either of the methods based on some information to indicate how the message was originally sent.

Related

Deserialization message contract first grpc approach

In the grpc contract first approach is there any way to convert into custom C# object from autogenerated c# object from the proto message.
Type to deserialize
class HelloRep
{
string message { get; set; }
}
proto message
message HelloReply {
string message = 1;
}
Client code
var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new Greeter.GreeterClient(channel);
var reply = client.SayHello(new HelloRequest { Name = "xx" });
Searching for a method to convert reply into HelloRep.
ex : HelloRep hello = Serializer.Deserialize<HelloRep>(reply);
I'm less familiar with C#. In other languages (Golang, Python etc.), protoc generates additional fields|methods that preclude automatic conversion.
Using custom classes, you get flexibility of field|method naming and type conversions if you want them.

problem with masstransit dynamic event publish ( json event )

we need publish multiple event as json string from DB. publish this json event by masstransit like this:
using var scope = _serviceScopeFactory.CreateScope();
var sendEndpointProvider = scope.ServiceProvider.GetService<ISendEndpointProvider>();
var endpoint = await sendEndpointProvider.GetSendEndpoint(new System.Uri("exchange:IntegrationEvents.DynamicEvent:DynamicEvent"))
var json = JsonConvert.SerializeObject(dynamicObject, Newtonsoft.Json.Formatting.None);// sample
var obj = JsonConvert.DeserializeObject(json, new JsonSerializerSettings { });
await endpoint.Send(obj,i=>i.Serializer.ContentType.MediaType= "application/json");
and in config we use this config:
cfg.UseRawJsonSerializer();
when use this config, json event is successful published but we have strange problem : "all" event consumer is called by empty message data ! ... in Rabbitmq jsut published our "Dynamic Event", but in masstrasit all consumers called !!
Thank you for letting us know if we made a mistake
You don't need all of that JSON manipulation, just send the message object using the endpoint with the serializer configured for RawJson. I cover JSON interoperability in this video.
Also, MassTransit does not allow anonymous types to be published. You might be able to publish dynamic or Expando objects.
I used ExpandoObject like this and get this exception "Messages types must not be in the System namespace: System.Dynamic.ExpandoObject" :
dynamic dynamicObject = new ExpandoObject();
dynamicObject.Id = 1;
dynamicObject.Name = "NameForName";
await endpoint.Send(dynamicObject);
and using like this we get same result as "all consumers called":
var dynamicObject = new ExpandoObject() as IDictionary<string, object>;
dynamicObject.Add("Id", 1);
dynamicObject.Add("Name", "NameForName");
I watch your great video, you used from rabbitmq directly .. how "send the message object using the endpoint with the serializer configured for RawJson" in C# code.

Send Microsoft.Azure.ServiceBus Message to BizTalk 2013 WCF-Custom

I need to send messages from a .NET Core app via the Azure Service Bus to BizTalk 2013. I have configured a WCF Custom receive port on BizTalk but on receiving a message get the following error:
The adapter "WCF-Custom" raised an error message. Details "System.Xml.XmlException: The input source is not correctly formatted.
I've found examples using Windows.Azure.ServiceBus package and BrokeredMessage, but this is deprecated. I need to use Microsoft.Azure.ServiceBus and the Message object.
I've tried many ways of serializing the XML but nothing seems to work.
In short I'm creating the message like this:
var message = new Message(Encoding.UTF8.GetBytes("<message>Hello world</message>"));
Is there a way to serialize the message correctly to be received by WCF in BizTalk 2013?
I figured it out.
For anyone who needs to send messages via Azure Service Bus using Microsoft.Azure.ServiceBus Message to BizTalk 2013 WCF-Custom receive port.
var toAddress = "sb://yourbusname.servicebus.windows.net/yourqueuename";
var bodyXml = SerializeToString(yourSerializableObject); //
var soapXmlString = string.Format(#"<s:Envelope xmlns:s=""http://www.w3.org/2003/05/soap-envelope"" xmlns:a=""http://www.w3.org/2005/08/addressing""><s:Header><a:Action s:mustUnderstand=""1"">*</a:Action><a:To s:mustUnderstand=""1"">{0}</a:To></s:Header><s:Body>{1}</s:Body></s:Envelope>",
toAddress, bodyXml);
var content = Encoding.UTF8.GetBytes(soapXmlString);
var message = new Message { Body = content };
message.ContentType = "application/soap+msbin1";
This wraps the Xml in a proper SOAP format. Note the "to" embedded in the SOAP envelope is necessary (I found it didn't work using message.To).
For completeness, this is the serialization method (for clean xml):
public string SerializeToString<T>(T value)
{
var emptyNamespaces = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
var serializer = new XmlSerializer(value.GetType());
var settings = new XmlWriterSettings
{
Indent = false,
OmitXmlDeclaration = true
};
using (var stream = new StringWriter())
using (var writer = XmlWriter.Create(stream, settings))
{
serializer.Serialize(writer, value, emptyNamespaces);
return stream.ToString();
}
}

Marketo rest Api create lead

I have a question about this create/Update leads API, http://developers.marketo.com/documentation/rest/createupdate-leads/.
There is no sample code for C# or JAVA. Only ruby available. So I have to try it by myself. But I always get null return from the response.
Here is my code:
private async Task<CreateLeadResponseResult> CreateLead(string token)
{
string url = String.Format(marketoInstanceAddress+"/rest/v1/leads.json?access_token={0}", token);
var fullUri = new Uri(url, UriKind.Absolute);
CreateLeadResponseResult createLeadResponse = new CreateLeadResponseResult();
CreateLeadInput input = new CreateLeadInput { email = "123#123.com", lastName = "Lee", firstName = "testtesttest", postCode = "00000" };
CreateLeadInput input2 = new CreateLeadInput { email = "321#gagaga.com", lastName = "Lio", firstName = "ttttttt", postCode = "00000" };
List<CreateLeadInput> inputList = new List<CreateLeadInput>();
inputList.Add(input);
inputList.Add(input2);
CreateLeadRequest createLeadRequest = new CreateLeadRequest() { input = inputList };
JavaScriptSerializer createJsonString = new JavaScriptSerializer();
string inputJsonString = createJsonString.Serialize(createLeadRequest);
using (var client = new HttpClient())
{
HttpResponseMessage response = await client.PostAsJsonAsync(fullUri.OriginalString, inputJsonString).ConfigureAwait(false);
// I can see the JSON string is in the message body in debugging mode.
if (response.IsSuccessStatusCode)
{
createLeadResponse = await response.Content.ReadAsAsync<CreateLeadResponseResult>();
}
else
{
if (response.StatusCode == HttpStatusCode.Forbidden)
throw new AuthenticationException("Invalid username/password combination.");
else
throw new ApplicationException("Not able to get token");
}
}
return createLeadResponse;}
//get null here.
Thank you.
-C.
The best way to debug this is to capture the exact URL, parameters and JSON that are submitted by your app and try submitting those manually via a tool like Postman (Chrome plug-in) or SOAP UI. Then you see the exact error message, which you can look up here: http://developers.marketo.com/documentation/rest/error-codes/. Based on that you can update your code. I don't know much about Java, but this is how I got my Python code to work.
Your example code was really helpful in getting my own implementation off the ground. Thanks!
After playing with it for a bit, I realized that the JavaScriptSerializer step is unnecessary since PostAsJsonAsync automatically serializes whatever object you pass to it. The double serialization prevents Marketo's API from processing the input.
Also, I agree with Jep that Postman is super helpful. But in the case of this error, Postman was working fine (using the contents of inputJsonString) but my C# code still didn't work properly. So I temporarily modified the code to return a dynamic object instead of a CreateLeadResponseResult. In debugging mode this allowed me to see fields that were discarded because they didn't fit the CreateLeadResponseResult type, which led me to the solution above.

Exposing object of unknown type from a WCF service

[OperationContract]
public object GetDeserializedObject(int partyContactID)
{
PartyContact partyContact = GetPartyContactById(partyContactID);
ContactTermResultQueue resultQueue = GetContactTermResultQueueByID(partyContact.TemplateQueueID);
byte[] contactDataSetArray = resultQueue.QueryResult;
//Getting DataSet from the byte array
BinaryFormatter binaryFormatter = new BinaryFormatter();
Stream mStreamtoRead = new MemoryStream(contactDataSetArray);
object o = binaryFormatter.Deserialize(mStreamtoRead);
mStreamtoRead.Close();
object returnData=null;
if (o.GetType().IsArray)
{
object[] os = o as object[];
var value = from vs in os where (int) (vs.GetType().GetProperty("PartyID").GetValue(vs, null)) == partyContact.PartyID select vs;
if (value.Count() > 0)
{
returnData = value.First();
}
}
return returnData;
}
As I don't know what type of data we are going to have in the database, so wanted to return the object from this service, but it is giving me an exception.
Please let me know how can I achieve this?
Thanks in advance
You can't return object and expect it will work. The reason is that behind this code WCF engine uses serialization. When client receives message it must be able to deserialize it back to some object but to be able to do that it must know what type of object it received.
If you want to send "unknown" data use XElement. Client will receive just XML and it will be its responsibility to deal with it (parse it, deserialize it or whatever).
You can do certain things with the "raw" Message data type - but it's really not pretty programming...
Read about it here:
How to pass arbitrary data in a Message object using WCF
WCF : Untyped messages on WCF operations.