I got this error upon receving an object from a subscription in azure service bus.
An exception of type 'System.Runtime.Serialization.SerializationException' occurred in System.Runtime.Serialization.dll but was not handled in user code
I've tried some deserialization code but nothing works.
This is how I send a message. Please tell me how to receive it.
public void SendMessage()
{
BrokeredMessage message = new BrokeredMessage(new TestMessage() {
MsgNumber = 1, MsgContent = "testing message" }, new DataContractSerializer(typeof(TestMessage)));
// Send message to the topic
TopicClient topicClient = TopicClient.CreateFromConnectionString(cn, topicNamespace);
topicClient.Send(message);
}
public string ReceiveMessage(){
//??????
}
To receive a single message, you need to get the SubscriptionClient :
public void ReceiveMessage(string connectionString, string topicPath, string subscriptionName)
{
var subscriptionClient = SubscriptionClient.CreateFromConnectionString(connectionString, topicPath, subscriptionName);
var brokeredMessage = subscriptionClient.Receive();
var message = brokeredMessage.GetBody<TestMessage>();
}
Related
I am using NServiceBus for a proof of concept. I am using it with MSMQ. I Have a Web Application which send a message. This message will be handled by a subscriber or message handler. When i shutdown the message handler, message will be send to Error Queue after few retries.
I don't want to send it to error queue, i want to keep message in Input queue as long as Handler is again online and process this message automatically from input queue. If message can not be processed from handler due to any error, it must transfer message to error queue.
Here is my configuration in MVC application Global.asax
private void ConfigureServiceBus()
{
var endpointConfiguration = new EndpointConfiguration("Samples.Mvc.Endpoint");
endpointConfiguration.UseSerialization<JsonSerializer>();
endpointConfiguration.UsePersistence<InMemoryPersistence>();
endpointConfiguration.UseTransport<MsmqTransport>();
endpointConfiguration.SendFailedMessagesTo("error");
endpointConfiguration.AuditProcessedMessagesTo("audit");
var recoverability = endpointConfiguration.Recoverability();
recoverability.Delayed(
delayed =>
{
delayed.NumberOfRetries(2);
delayed.TimeIncrease(TimeSpan.FromSeconds(2));
});
endpointConfiguration.EnableInstallers();
endpoint = Endpoint.Start(endpointConfiguration).GetAwaiter().GetResult();
//var endpointInstance = Endpoint.Start(endpointConfiguration).ConfigureAwait(false);
var mvcContainerBuilder = new ContainerBuilder();
mvcContainerBuilder.RegisterInstance(endpoint);
// Register MVC controllers.
mvcContainerBuilder.RegisterControllers(typeof(MvcApplication).Assembly);
var mvcContainer = mvcContainerBuilder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(mvcContainer));
}
This is the part in Controller where i send message to endpoint.
[HttpPost]
public async Task<ActionResult> Contact(ContactModel c)
{
if (ModelState.IsValid)
{
try
{
var message = new ContactMessage()
{
Comment = c.Comment,
Email = c.Email,
FirstName = c.FirstName,
LastName = c.LastName,
TransectionId = Guid.NewGuid()
};
await endpoint.Send("Samples.Mvc.Endpoint", message).ConfigureAwait(false);
return View("Success");
}
catch (Exception ex)
{
return View("Error");
}
}
return View();
}
My goal is to keep unhandled messages in input queue as long as message handler is not back on work. currently if message handler is down, it send messages after retries to Error Queue.
I am using NServiceBus 6.x
thanks in advance
I have a Custom ClientMessageInspector that records requests but not replies to my service.
The code is:
namespace MessageListener.Instrumentation
{
public class MessageInspector : IClientMessageInspector
{
private Message TraceMessage(MessageBuffer buffer)
{
// Must use a buffer rather than the original message, because the Message's body can be processed only once.
Message msg = buffer.CreateMessage();
using (RREM_GilbaneEntities3 entities3 = new RREM_GilbaneEntities3())
{
SOAPMessage soapMessages = new SOAPMessage
{
SOAPMessage1 = msg.ToString(),
created = DateTime.Now,
source = "Interface12",
sourceIP = "Interface12"
};
entities3.SOAPMessages.Add(soapMessages);
entities3.SaveChanges();
}
//Return copy of origonal message with unalterd State
return buffer.CreateMessage();
}
public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
reply = TraceMessage(reply.CreateBufferedCopy(int.MaxValue));
}
public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
request = TraceMessage(request.CreateBufferedCopy(int.MaxValue));
return null;
}
}
}
What seems to be happening is both AfterRecievReply and BeforeSendRequest are being called. In AfterRecieveReply before I call TraceMessage, I can see the whole reply. Inside TraceMessage, when I do:
// Must use a buffer rather than the original message, because the Message's body can be processed only once.
Message msg = buffer.CreateMessage();
it turns the reply into junk:
msg {<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header />
<soap:Body>... stream ...</soap:Body>
</soap:Envelope>}
What's going on?
The reply isn't a junk message - it's just when you call ToString on it that it doesn't show the body of the message. Remember that a message can only be consumed once; once its body is read, it cannot be read again. Since many places (including the watch window of debuggers) will call ToString on an object, this method is implemented in a way that if it doesn't know for sure that a message body can be read multiple times, then it won't, which seems to be your case. If you want to really write out the message, try using this code:
public string MessageToString(Message message) {
using (MemoryStream ms = new MemoryStream()) {
XmlWriterSettings ws = new XmlWriterSettings();
ws.Encoding = new UTF8Encoding(false);
using (XmlWriter w = XmlWriter.Create(ms)) {
message.WriteMessage(w);
w.Flush();
return ws.Encoding.GetString(ms.ToArray());
}
}
}
While creating a GCM client application, asynctask is giving compilation errors.
OnCreate we are calling registerBackgrouod which will check whether gcm instance is running or not, if not create one.
But asyntask is giving error : "Asynctask cannot be resolved to a type"
private void registerBackground() {
new AsyncTask() {
protected String doInBackground(Void... params) {
String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(context);
}
regid = gcm.register(SENDER_ID);
msg = "Device registered, registration id=" + regid;
// You should send the registration ID to your server over HTTP,
// so it can use GCM/HTTP or CCS to send messages to your app.
// For this demo: we don't need to send it because the device
// will send upstream messages to a server that echo back the message
// using the 'from' address in the message.
// Save the regid - no need to register again.
setRegistrationId(context, regid);
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
}
return msg;
}
protected void onPostExecute(String msg) {
mDisplay.append(msg + "\n");
}
}.execute(null, null, null);
As already observed by the AlexBcn, and according to the documentation of AsyncTask, you would pass to the AsyncTask three types as param. Because you want to return the payload of the GCM push notification as a String, you would invoke AsyncTask<Void, Void, String>
So the correct code snippet of GCM client is:
private void registerInBackground() {
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(context);
}
regid = gcm.register(SENDER_ID);
msg = "Device registered, registration ID=" + regid;
// You should send the registration ID to your server over HTTP, so it
// can use GCM/HTTP or CCS to send messages to your app.
// For this demo: we don't need to send it because the device will send
// upstream messages to a server that echo back the message using the
// 'from' address in the message.
// Persist the regID - no need to register again.
storeRegistrationId(context, regid);
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
// If there is an error, don't just keep trying to register.
// Require the user to click a button again, or perform
// exponential back-off.
}
return msg;
}.execute(null, null, null);
}
This is because of the params you pass in to Async task.
For further help:
I recently uploaded the fully functional GCM java client to my Github Account:
GCM Android Client
It has got both server and client implementation.
I am using the solution from the ServiceStack Re-usability use case project.
To this solution I have added a new console app which contains the code below.
With the original Re-usability use-case project, when an EmailMessage is published it was handled by a subscriber which sent an email (i.e. SMessageService.Any(EmailMessage request).
When I run the console app, which means I have two applications that are subscribing to the EmailMessage, only the new console app receives the message.
I have the following:
My console app is:
class Program
{
static void Main(string[] args)
{
var subscriberHost = new SubscriberHost();
subscriberHost.Init();
Console.WriteLine("Waiting of publishing
to happen on EmailMessage as we are subscribing to it...");
Console.ReadLine();
}
}
public class SubscriberHost : AppHostHttpListenerBase
{
private RedisMqServer mqHost;
public SubscriberHost()
:base("Subscriber console",typeof(EmailMessageEventHandler).Assembly)
{
}
public override void Configure(Container container)
{
var redisFactory = new PooledRedisClientManager("localhost:6379");
mqHost = new RedisMqServer(redisFactory, retryCount:2);
mqHost.RegisterHandler<EmailMessage>((message) =>
{
var emailMessage = message.GetBody();
Console.WriteLine(emailMessage.To);
Console.WriteLine(emailMessage.Subject);
Console.WriteLine(emailMessage.Body);
return new SMessageReceipt {
Type = "not used",
To = "test",
From = "Reusability",
RefId = "1,"
};
});
// mqHost.RegisterHandler<EmailMessage>(ServiceController.ExecuteMessage);
mqHost.Start();
}
}
I was expecting both subscribers to receive the EmailMessage but only the new console app is receiving it. Why isn't the other subscriber receiving the message?
The client code that does the publishing has not been modified.
What I have shown above is using Redis MQ, and for the multiple subscribers problem I was testing I need the Redis Pub/Sub.
For MQ, a subscriber takes the message off the queue to process. Once processed, that is it.
For Pub/Sub, there could be many subscribers and each will receive a copy of the message.
I hope this helps others.
I have a project where I should write WCF service that calls another WCF service. It looks as following:
[ServiceContract]
public interface IAsurService
{
[OperationContract(ReplyAction = AsurService.ReplyAction_GetCatalogList)]
Message GetCatalogList();
public Message GetCatalogList()
{
// The external client service
GetNsiClient client = new GetNsiClient();
authContext auth = new authContext
{
company = "asur_nsi",
password = "lapshovva",
user = "dogm_LapshovVA"
};
catalogs catalogs = client.getCatalogList(auth);
How can I handle errors in this case? Can I use standard fault contract approach like this:
[DataContract]
public class AsurDataFaultException
{
private string reason;
[DataMember]
public string Reason
{
get { return reason; }
set { reason = value; }
}
}
public Message GetCatalogList()
{
// The external client service
GetNsiClient client = new GetNsiClient();
authContext auth = new authContext
{
company = "asur_nsi",
password = "lapshovva",
user = "dogm_LapshovVA"
};
catalogs catalogs = null;
try
{
catalogs = client.getCatalogList(auth);
}
catch (Exception exception)
{
AsurDataFaultException fault = new AsurDataFaultException();
fault.Reason = "The error: " + exception.Message.ToString();
throw new FaultException<AsurDataFaultException>(fault);
}
Or something else?
Thank you in advance.
Goran
If the remote WCF service's failure causes a failure of your code, then obviously you should throw a fault but that fault should not expose the inner details of the remote WCF service or its exception, like so:
catch (Exception exception)
{
// Indicate all that you may expose -- that the data is unavailable.
DataUnavailableFault fault = new DataUnavailableFault();
throw new FaultException<DataUnavailableFault>(fault);
}
You may of course also use a retry mechanism, but obviously if what you end up with is a failure in the remote service, you should indicate that to your caller by throwing an appropriate fault.