In my WCF REST service, there is a method GetUser(username), which will
throw new WebFaultException<string>("there is no this user", HttpStatusCode.NotFound);
In my asp.net client, I want to catch above exception and show "there is no this user" on a label. But when I try coding as follow:
MyServiceClient client = new MyServiceClient;
try
{
client.GetUser(username);
}
catch (Exception ex)
{
Label.Text = ex.Message;
}
It turns out show the message "NotFound" instead of "there is no this user".
How can i do to show the message "there is no this user"?
20/4
In my REST service:
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json,
UriTemplate = "{username}")]
void GetUser(username);
.svc class :
public void GetUser(username)
{
try
{
Membership.GetUser(username);
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.OK;
}
catch (Exception ex)
{
throw new WebFaultException<string>("there is no this user", HttpStatusCode.NotFound);
}
}
If you look into the documentation, it's obvious that you should be showing the Detail, not the Message. Your line should be:
MyServiceClient client = new MyServiceClient;
try
{
client.GetUser(username);
}
catch (FaultException<string> ex)
{
var webFaultException = ex as WebFaultException<string>;
if (webFaultException == null)
{
// this shouldn't happen, so bubble-up the error (or wrap it in another exception so you know that it's explicitly failed here.
rethrow;
}
else
{
Label.Text = webFaultException.Detail;
}
}
EDIT: changed exception type
Also, you should be catching the specific exception (WebFaultException<string>) that you're interested in, not any-old exception that happens to be thrown. Especially, as you'll only have the Detail on the WebFaultException<string> type, it's not on Exception.
See the WebFaultException Class
Related
I have a BizTalk Custom Pipeline Component that writes an SFTP file (using SSH.net), triggered by an SFTP (WinSCP) receive location.
The code within the Retry occasionally (around half the time) does not hit either the "Success" nor the logging catch block and no further processing occurs within the Pipeline. I assume that means the thread has been destroyed.
I added the Retry code later to make it try a few times but with the thread being destroyed I don't always get a success or 3 failures.
What could cause this behaviour in BizTalk 2016?
public void Archive(byte[] content,
string archivePath,
string userName,
string password,
string serverAddress,
string sshHostKeyFingerprint)
{
Retry(3, () =>
{
try
{
using (var sftpClient = new SftpClient(serverAddress, userName, password))
{
if (!string.IsNullOrWhiteSpace(sshHostKeyFingerprint))
{
sshHostKeyFingerprint = sshHostKeyFingerprint.Split(' ').Last();
sftpClient.HostKeyReceived += delegate (object sender, HostKeyEventArgs e)
{
if (e.FingerPrint.SequenceEqual(ConvertFingerprintToByteArray(sshHostKeyFingerprint)))
e.CanTrust = true;
else
e.CanTrust = false;
};
}
sftpClient.Connect();
sftpClient.WriteAllBytes(archivePath, content);
sftpClient.Disconnect();
LogInfo($"Success");
}
}
catch (Exception exception)
{
// show the bad path for "No such file" errors
throw new InvalidOperationException($"Failed to create file '{archivePath}'", exception);
}
});
}
private void Retry(int maxAttempts, Action action)
{
int attempt = 1;
while (attempt <= maxAttempts)
{
try
{
action();
break; // success
}
catch (Exception exception)
{
LogWarning($"Attempt {attempt} Error: {exception.ToString()}");
if (attempt == maxAttempts)
throw; // final attempt exception propagated
}
finally
{
attempt++;
}
}
}
I have this code in my application. If the insert fails, I would like to add information about the failure to the Audit table. Perhaps the inner exception message from the exception in the note area. Is there a way that I could do this and then still have the procedure exit with that same exception details back to the caller?
[Route("Post")]
[ValidateModel]
public async Task<IHttpActionResult> Post([FromBody]Phrase phrase)
{
phrase.StatusId = (int)EStatus.Saved;
UpdateHepburn(phrase);
db.Phrases.Add(phrase);
var audit = new Audit()
{
Entity = (int)EEntity.Phrase,
Action = (int)EAudit.Insert,
Note = phrase.English,
UserId = userId,
Date = DateTime.UtcNow,
Id = phrase.PhraseId
};
db.Audits.Add(audit);
await db.SaveChangesAsync();
return Ok(phrase);
}
You can catch the original exception and rethrow it afterwards:
try
{
await db.SaveChangesAsync();
}
catch (Exception)
{
try
{
// TODO: add to the audit here, also in a try/catch as this might fail as well
}
catch
{
}
// rethrow the original exception
throw;
}
I have several methods in a controller that look like:
[HttpPost]
public ActionResult AddEditCommentToInvoice(string invoiceNumber, string comments)
{
var response = new { success = true, msg = "Comment saved", statusMsg = "Comment saved" };
try
{
var recordsModified = invoiceService.AddCommentsToInvoice(invoiceNumber, comments);
Log.Info(recordsModified ? "Updated Comment" : "Did not update Comment");
} catch (Exception ex) {
Response.StatusCode = (int)HttpStatusCode.InternalServerError;
return Json(new {
success = false,
msg = "There is missing field data",
statusMsg = ex.Message
}, JsonRequestBehavior.AllowGet);
}
return Json(response, JsonRequestBehavior.AllowGet);
}
While this code works, I'm not comfortable with this approach because:
Try/Catches are expensive
The code catches System.Exception
The code is ugly
Now I know that I can use OnException or the HandleError attribute.
I also did some research on ELMAH and this looks promising.
But I still want to return JSON via AJAX to my user to indicate whether the operation was a success or not.
So my question is, has anyone used any of the three methods (or specifically ELMAH) to return JSON via AJAX?
I use another approach that's an approach that can be applied at the controller level or globally through GlobalFilters. In my MVC controllers, you could override OnActionExecuted method, and do this:
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Exception != null)
{
filterContext.Result = Json(new { success = false });
return;
}
base.OnActionExecuted(filterContext);
}
This could also be done as an action filter attribute. You wouldn't need any exception handling in your controllers - if an exception occurs, then this is handled within the context of the result.
I have a wrapper for the webclient that I am using to retrieve some data. This same function is being used by the WP8 App and also used by the WP8 ScheduledAgent.
Somehow, when the function is used by the WP8 App, there is no error and it returns correctly.
However, when the ScheduledAgent uses the function, it erred out at the bold code below. I tried a try catch but it is not catching. Via Debugger, the GetSTringAsync(uri) had completed without any exception. The error seemed to be only happening when it is assigning the return Task to the result string.
The error I received is:
An unhandled exception of type 'System.UnauthorizedAccessException' occurred in System.Windows.ni.dll
public class HttpClient : WebClient
..
private async Task GetStringAsync(string strUri)
{
Uri uri = new Uri(strUri);
string result = string.Empty;
try
{
result = await GetStringAsync(uri);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return result;
}
...
private Task GetStringAsync(Uri requestUri)
{
TaskCompletionSource tcs = new TaskCompletionSource();
try
{
this.DownloadStringCompleted += (s, e) =>
{
if (e.Error == null)
{
tcs.TrySetResult(e.Result);
}
else
{
tcs.TrySetException(e.Error);
}
};
this.DownloadStringAsync(requestUri);
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
if (tcs.Task.Exception != null)
{
throw tcs.Task.Exception;
}
return tcs.Task;
}
Please advise if I am missing something.
My problem is because I am using pushpin as one of my object types within my Model. Apparently, in the scheduled agent, it is not able to access that object type and thus threw the above error.
I am a new to WCF. I have written ajax to use a web service before, but on this project I am trying to use ajax to WCF.
After I build the project and wcf using ajax, I receive the return successfully. But, 10 or more minutes later I don't get a return, the ajax calls the error function, and the fiddler returns nothing.
If I rebuild the project without any source modifying, I receive the return successfully again.
Is their anybody who has experienced this or knows why this might be?
Thank You.
Most likely you're not closing the connections. You should wrap all your calls in Try/Catch/Finally blocks.
In C#:
ServiceClient service = GetService();
try
{
SomeRequest request = new SomeRequest();
SomeResponse response = service.GetSome(request);
return response.Result;
}
catch (Exception ex)
{
// do some error handling
}
finally
{
try
{
if (service.State != CommunicationState.Faulted)
{
service.Close();
}
}
catch (Exception ex)
{
service.Abort();
}
}
or VB
Dim service As ServiceClient = GetService()
Try
Dim request As New SomeRequest()
Dim response As SomeResponse = service.GetSome(request)
Return response.Result
Catch ex As Exception
' do some error handling
Finally
Try
If service.State <> CommunicationState.Faulted Then
service.Close()
End If
Catch ex As Exception
service.Abort()
End Try
End Try
Here is the best practice for calling WCF services:
public static void CallService<T>(Action<T> action) where T
: class, ICommunicationObject, new()
{
var client = new T();
try
{
action(client);
client.Close();
}
finally
{
if (client.State == CommunicationState.Opened)
{
try
{
client.Close();
}
catch (CommunicationObjectFaultedException)
{
client.Abort();
}
catch (TimeoutException)
{
client.Abort();
}
}
if (client.State != CommunicationState.Closed)
{
client.Abort();
}
}
}
Each WCF call should create a new instance of your service class. This code allows you to enforce that and just call the services like this:
CallService<MyService>( t => t.CallMyService());