I'm almost finished my first WP7 application and I'd like to publish it to the marketplace. However, one of the stipulations for a published app is that it must not crash unexpectedly during use.
My application almost completely relies on a WCF Azure Service - so I must be connected to the Internet at all times for my functions to work (communicating with a hosted database) - including login, adding/deleting/editing/searching clients and so forth.
When not connected to the internet, or when the connection drops during use, a call to the web service will cause the application to quit. How can I handle this? I figured the failure to connect to the service would be caught and I could handle the exception, but it doesn't work this way.
LoginCommand = new RelayCommand(() =>
{
ApplicationBarHelper.UpdateBindingOnFocussedControl();
MyTrainerReference.MyTrainerServiceClient service = new MyTrainerReference.MyTrainerServiceClient();
// get list of clients from web service
service.LoginCompleted += new EventHandler<LoginCompletedEventArgs>(service_LoginCompleted);
try
{
service.LoginAsync(Email, Password);
}
**catch (Exception ex)
{
throw new Exception(ex.Message);
}**
service.CloseAsync();
});
EDIT:
My main problem is how to handle the EndpointNotFoundException in WP7 without the application crashing.
Thanks,
Gerard.
Your code should look like
LoginCommand = new RelayCommand(Login);
...
public void Login()
{
var svc = new MyTrainerReference.MyTrainerServiceClient();
try
{
svc.LoginCompleted += LoginCompleted;
svc.LoginAsync();
}
catch (Exception e)
{
svc.CloseAsync();
ShowError(e);
}
}
private void LoginCompleted(object sender, LoginCompletedEventArgs e)
{
((MyTrainerReference.MyTrainerServiceClient)sender).LoginCompleted -= LoginCompleted;
((MyTrainerReference.MyTrainerServiceClient)sender).CloseAsync();
if (e.Error == null && !e.Cancelled)
{
// TODO process e.Result
}
else if (!e.Cancelled)
{
ShowError(e.Error);
}
}
private void ShowError(Exception e)
{
// TODO show error
MessageBox.Show(e.Message, "An error occured", MessageBoxButton.OK);
}
Your code calls LoginAsync and then immediately CloseAsync, I think this will cause problems...
Related
I'm trying to write an infinite length response body and detect when a client disconnects so I can stop writing. I'm used to getting socket exceptions or similar when a client closes the connection but that doesn't seem to be happening when writing directly to Response.Body. I can close the client applications and the server side just keeps on writing. I've included the relevant code below. It's entirely possible there is a better way to do it but this came to mind. Basically I have a live video feed which should go on forever. I'm writing to ResponseBody as chunked content (No content length, flushing after each video frame). The video frames are received via an event callback from elsewhere in the program so I'm subscribing to the events in the controller method and then forcing it to stay open with the await Task.Delay loop so the Response stream isn't closed. The callback for H264PacketReceived is formatting the data as a streaming mp4 file and writing it to the Response Stream. This all seems to work fine, I can play the live stream with ffmpeg or chrome, but when I close the client application I don't get an exception or anything. It just keeps writing to the stream without any errors.
public class LiveController : ControllerBase
{
[HttpGet]
[Route("/live/{cameraId}/{stream}.mp4")]
public async Task GetLiveMP4(Guid cameraId, int stream)
{
try
{
Response.StatusCode = 200;
Response.ContentType = "video/mp4";
Response.Headers.Add("Cache-Control", "no-store");
Response.Headers.Add("Connection", "close");
ms = Response.Body;
lock (TCPVideoReceiver.CameraStreams)
{
TCPVideoReceiver.CameraStreams.TryGetValue(cameraId, out cameraStream);
}
if (this.PacketStream == null)
{
throw new KeyNotFoundException($"Stream {cameraId}_{stream} not found");
}
else
{
connected = true;
this.PacketStream.H264PacketReceived += DefaultStream_H264PacketReceived;
this.PacketStream.StreamClosed += PacketStream_StreamClosed;
}
while(connected)
{
await Task.Delay(1000);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
finally
{
connected = false;
this.PacketStream.H264PacketReceived -= DefaultStream_H264PacketReceived;
this.PacketStream.StreamClosed -= PacketStream_StreamClosed;
}
}
private bool connected = false;
private PacketStream PacketStream;
private Mp4File mp4File;
private Stream ms;
private async void PacketStream_StreamClosed(PacketStream source)
{
await Task.Run(() =>
{
try
{
Console.WriteLine($"Closing live stream");
connected = false;
ms.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
});
}
private async void DefaultStream_H264PacketReceived(PacketStream source, H264Packet packet)
{
try
{
if (mp4File == null && packet.IsIFrame)
{
mp4File = new Mp4File(null, packet.sps, packet.pps);
var _p = mp4File.WriteHeader(0);
await ms.WriteAsync(mp4File.buffer, 0, _p);
}
if (mp4File != null)
{
var _p = mp4File.WriteFrame(packet, 0);
var start = mp4File._moofScratchIndex - _p;
if (_p > 0)
{
await ms.WriteAsync(mp4File._moofScratch, start, _p);
await ms.FlushAsync();
}
}
return;
}
catch (Exception ex)
{
connected = false;
Console.WriteLine(ex.ToString());
}
}
Answering my own question.
When the client disconnects mvc core sets the cancellation token HttpContext.RequestAborted
By monitoring and/or using that cancellation token you can detect a disconnect and clean everything up.
That said, the entire design can be improved by creating a custom stream which encapsulates the event handling (producer/consumer). Then the controller action can be reduced to.
return File(new MyCustomStream(cameraId, stream), "video/mp4");
The File Method already monitors the cancellation token and everything works as you'd expect.
I am very new to NService Bus, so I am trying to get it working with a simple test solution using LearningPersistence, obviously this will be changed soon!
So I have 3 projects:
IceDataExtractor - Client which sends a message
IceProcessManager - Processes messages
Messages - Contains a single Message class Messages
I am using the standard code generated by NServiceBus.Bootstrap.WindowsService 2.0.1
Here is page I used as to get sample
I then modified as follows
Ice Data Extractor
private async Task AsyncOnStart()
{
try
{
var endpointConfiguration = new EndpointConfiguration("IceDataExtractor");
var transport = endpointConfiguration.UseTransport<LearningTransport>();
transport.Routing().RouteToEndpoint(typeof(TestMessage), "IceProcessManager");
endpointConfiguration.UseSerialization<JsonSerializer>();
//TODO: optionally choose a different error queue. Perhaps on a remote machine
// https://docs.particular.net/nservicebus/recoverability/
endpointConfiguration.SendFailedMessagesTo("error");
//TODO: optionally choose a different audit queue. Perhaps on a remote machine
// https://docs.particular.net/nservicebus/operations/auditing
endpointConfiguration.AuditProcessedMessagesTo("audit");
endpointConfiguration.DefineCriticalErrorAction(OnCriticalError);
//TODO: For production use select a durable persistence.
// https://docs.particular.net/nservicebus/persistence/
endpointConfiguration.UsePersistence<LearningPersistence>();
//TODO: For production use script the installation.
endpointConfiguration.EnableInstallers();
endpointConfiguration.Conventions()
.DefiningCommandsAs(t => t.Namespace != null && t.Namespace.StartsWith("Messages") &&
t.Namespace.EndsWith("Commands"));
endpoint = await Endpoint.Start(endpointConfiguration)
.ConfigureAwait(false);
PerformStartupOperations();
**var testMessage = new TestMessage {Id = Guid.NewGuid()};
await endpoint.Send(testMessage).ConfigureAwait(false);**
}
catch (Exception exception)
{
logger.Fatal("Failed to start", exception);
Environment.FailFast("Failed to start", exception);
}
}
Ice Process Manager
private async Task AsyncOnStart()
{
try
{
var endpointConfiguration = new EndpointConfiguration("IceDataExtractor");
var transport = **endpointConfiguration.UseTransport<LearningTransport>();
transport.Routing().RouteToEndpoint(typeof(TestMessage), "IceProcessManager");**
endpointConfiguration.UseSerialization<JsonSerializer>();
//TODO: optionally choose a different error queue. Perhaps on a remote machine
// https://docs.particular.net/nservicebus/recoverability/
endpointConfiguration.SendFailedMessagesTo("error");
//TODO: optionally choose a different audit queue. Perhaps on a remote machine
// https://docs.particular.net/nservicebus/operations/auditing
endpointConfiguration.AuditProcessedMessagesTo("audit");
endpointConfiguration.DefineCriticalErrorAction(OnCriticalError);
//TODO: For production use select a durable persistence.
// https://docs.particular.net/nservicebus/persistence/
endpointConfiguration.UsePersistence<LearningPersistence>();
//TODO: For production use script the installation.
endpointConfiguration.EnableInstallers();
**endpointConfiguration.Conventions()
.DefiningCommandsAs(t => t.Namespace != null && t.Namespace.StartsWith("Messages") &&
t.Namespace.EndsWith("Commands"));**
endpoint = await Endpoint.Start(endpointConfiguration)
.ConfigureAwait(false);
PerformStartupOperations();
var testMessage = new TestMessage {Id = Guid.NewGuid()};
await endpoint.Send(testMessage).ConfigureAwait(false);
}
catch (Exception exception)
{
logger.Fatal("Failed to start", exception);
Environment.FailFast("Failed to start", exception);
}
}
TestMessage class
using System;
namespace Messages.Commands
{
public class TestMessage
{
public Guid Id { get; set; }
}
}
This all compiles and runs fine, other than performance warnings which I dont think matter
I have a message handler
TestMessageHandler
using System;
using System.Threading.Tasks;
using Messages.Commands;
using NServiceBus;
namespace IceProcessManager
{
public class TestMessageHandler : IHandleMessages<TestMessage>
{
public Task Handle(TestMessage message, IMessageHandlerContext context)
{
Console.WriteLine("Handled TEst MEssage ID:{0}", message.Id);
return Task.CompletedTask;
}
}
}
As you can see from the screenshot, no message is being received by the IceProcessManager. What am I doing wrong? I was thinking initially that I am sending the message too early, i.e. before the ProcessManager is up and running, but this not the problem because if I leave the ProcessManager running (i.e. run from explorer) then run the extractor, no message is receieved
Ideally I would like to have sent lots of messages to test this but I am not familiar with async stuff yet!
Can someone help please?
Paul
If I am not missing something you are using the same endpoint name for both instances?
var endpointConfiguration = new EndpointConfiguration("IceDataExtractor");
While you are routing the message to "IceDataManager" which doesn't exist.
I guess you might have pasted the wrong code?
I have a WCF request in WP8 environment that I wrapped according to this
http://msdn.microsoft.com/en-us/library/hh873178%28v=vs.110%29.aspx#EAP
My call to the WCF service proceeds as follows:
try
{
var result = await mWCFClient.PerformRequestAsync();
}
catch(Exception e)
{
}
where PerformRequestAsync is an extension method. i.e.
public static ResultType PerformRequestAsync(this WCFClient client)
{
// EAP wrapper code
}
What happens is that occasionally something goes wrong on the WCF service and it returns "NotFound". I am not 100% sure why this happens and it seems like a rare occasion. The problem, however, is not the WCF service behavior, but the fact that it breaks in the EndPerformRequestAsync() in the automatically generated WCF code instead of going to my exception handler.
How and where should I be catching this exception as it never reaches my intended handler?!
[Edit]
As per Stephen's request, I've included the wrapper code here:
public static Task<RegistrationResult> RegisterAsync(this StoreServiceReference.StoreServiceClient client, string token, bool dummy)
{
var tcs = new TaskCompletionSource<RegistrationResult>();
EventHandler<RegisterCompletedEventArgs> handler = null;
handler = (_, e) =>
{
client.RegisterCompleted -= handler;
if (e.Error != null)
tcs.TrySetException(e.Error);
else if (e.Cancelled)
tcs.TrySetCanceled();
else
tcs.TrySetResult(e.Result);
};
client.RegisterCompleted += handler;
PerformStoreRequest(client, () => client.RegisterAsync(), token);
return tcs.Task;
}
private static void PerformStoreRequest(StoreServiceClient client, Action action, string token)
{
using (new OperationContextScope(client.InnerChannel))
{
HttpRequestMessageProperty requestMessage = new HttpRequestMessageProperty();
requestMessage.Headers[STORE_TOKEN_HTTP_HEADER] = token;
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestMessage;
action.Invoke();
// TODO: Do we need to add handler here?
}
}
Now that I look at it, I think the problem stems from the nature of action invoke. But adding custom headers to WP8 WCF services already is a pain.
The action inside is an async operation, but Invoke as far as I know is not.
What's the proper way to go about it here?
I have a UI view lossreport.xaml in that below code is there
LossReportTowGlassServiceClient wcf = new LossReportTowGlassServiceClient();
wcf.HouseholdSearchCompleted += (o, ev) =>
{
string a = errorMessg.ToUpper();
//Code to work with ev
};
wcf.HouseholdSearchAsync(lossDate, txtPolicyNumber.Text, errorMessg);
in service.svc page
try
{
policyinq.retrieveHouseHoldPoliciesCompleted += new retrieveHouseHoldPoliciesCompletedEventHandler(policyinq_retrieveHouseHoldPoliciesCompleted);
policyinq.retrieveHouseHoldPoliciesAsync(reqh, searchCriteria, lossdate, true, string.Empty, string.Empty);
break;
}
catch (Exception ex)
{
Logger.Exceptions("", "HouseholdSearch", ex);
errorToSend = "Household error";
}
void policyinq_retrieveHouseHoldPoliciesCompleted(object sender, retrieveHouseHoldPoliciesCompletedEventArgs e)
{
{
if (e.transactionNotification != null && e.transactionNotification.transactionStatus == TransactionState.S)
{
}
else
{
ErrorHandling.ErrorSend(e.transactionNotification, "HouseHold");
}
};
}
now before retrieveHouseHoldPolicies is completed HouseholdSearchCompleted event is fired.How to make it wait
You have an architectural issue here, The service should not invoke async request unless you go ta good reason (maybe invoke some paralleled stuff. Just invoke your server side code synchronously.
A service entry point got it's own handler thread, it should be the one who starts and end the request response process on service side. what you do is call an async method on service side making the thread that handle the request finish his job. So you either make this thread wait or execute the entire logic on him without calling async method, kapish?
using System.Threading;
ManualResetEvent _wait = new ManualResetEvent(false);
_wait.Set();//In completed event
_wait.WaitOne();//After the event is completed WaitOne will wait untill the _wait is set with value
I've literally tried everything under the sun to get token based WS-Trust Web Services to work, to no avail. I can obtain a token from an STS, but the life of me, I can not figure out how make the WS server secure and accessible from the outside using a token.
So what I would love to know, is if anyone has ever got this to work on JBoss 7. I'm not interested in "this and that on jboss should give you some information". Been there done that - doesn't work. Have YOU been able to get it to work?
I looked at picketlink to secure web services using SAML but it appears to be exposing the SAML authentication using a JAAS security context. So instead I just wrote a custom handler using the picketlink API to secure the WS. The handler essentially does the same thing (i.e. saml assertion expiration and digital signature validation check) as the SAMLTokenCertValidatingCommonLoginModule available in picketlink jars but passes the SAML attributes into WS message context instead of passing it along as a JAAS security context.
Find below the code snippet.
See org.picketlink.identity.federation.bindings.jboss.auth.SAMLTokenCertValidatingCommonLoginModule
class of the picketlink-jbas-common source for implementation of methods getX509Certificate, validateCertPath used in the custom handler.
public class CustomSAML2Handler<C extends LogicalMessageContext> implements SOAPHandler {
protected boolean handleInbound(MessageContext msgContext) {
logger.info("Handling Inbound Message");
String assertionNS = JBossSAMLURIConstants.ASSERTION_NSURI.get();
SOAPMessageContext ctx = (SOAPMessageContext) msgContext;
SOAPMessage soapMessage = ctx.getMessage();
if (soapMessage == null)
throw logger.nullValueError("SOAP Message");
// retrieve the assertion
Document document = soapMessage.getSOAPPart();
Element soapHeader = Util.findOrCreateSoapHeader(document.getDocumentElement());
Element assertion = Util.findElement(soapHeader, new QName(assertionNS, "Assertion"));
if (assertion != null) {
AssertionType assertionType = null;
try {
assertionType = SAMLUtil.fromElement(assertion);
if (AssertionUtil.hasExpired(assertionType))
throw new RuntimeException(logger.samlAssertionExpiredError());
} catch (Exception e) {
logger.samlAssertionPasingFailed(e);
}
SamlCredential credential = new SamlCredential(assertion);
if (logger.isTraceEnabled()) {
logger.trace("Assertion included in SOAP payload: " + credential.getAssertionAsString());
}
try {
validateSAMLCredential(credential, assertionType);
ctx.put("roles",AssertionUtil.getRoles(assertionType, null));
ctx.setScope("roles", MessageContext.Scope.APPLICATION);
} catch (Exception e) {
logger.error("Error: " + e);
throw new RuntimeException(e);
}
} else {
logger.trace("We did not find any assertion");
}
return true;
}
private void validateSAMLCredential(SamlCredential credential, AssertionType assertion) throws LoginException, ConfigurationException, CertificateExpiredException, CertificateNotYetValidException {
// initialize xmlsec
org.apache.xml.security.Init.init();
X509Certificate cert = getX509Certificate(credential);
// public certificate validation
validateCertPath(cert);
// check time validity of the certificate
cert.checkValidity();
boolean sigValid = false;
try {
sigValid = AssertionUtil.isSignatureValid(credential.getAssertionAsElement(), cert.getPublicKey());
} catch (ProcessingException e) {
logger.processingError(e);
}
if (!sigValid) {
throw logger.authSAMLInvalidSignatureError();
}
if (AssertionUtil.hasExpired(assertion)) {
throw logger.authSAMLAssertionExpiredError();
}
}
}