I wanted to understand whether there are any better way to do logging or error handling in customized way with WCF
Here is the scenario.
I have a service as below
namespace IntegrationServices.Contract.SomeServices
{
[ServiceContract(Name = "SomeServices")]
public interface ISomeService
{
//Having 30+ contracts below is one of them
[OperationContract]
[WebInvoke(UriTemplate = "/GetOnlineSomething")]
SomeTransactionResponse GetOnlineSomething(string someNumber);
}
}
Which is implemented by below calss
namespace IntegrationServices.Service.PaymentServices
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
[GlobalErrorBehaviorAttribute(typeof(GlobalErrorHandler), Project.Name)]
public class PaymentService : ISomeService
{
public OnlinePaymentTransactionResponse GetOnlinePaymentTransaction(string someNumber)
{
//we have authentication code here which is OK
//Logging the request
_transactionKey = Guid.NewGuid();
TransactionRequest(/*some message and some parameter*/);
try
{
//do something
}
catch (Exception ex)
{
LogHelper.WriteErrorLogAsync(/*logging some more information*/);
response.ErrorMessage = Project.PHAPICommonErrorMessage;
}
//Logging the response
TransactionResponse(/*some parameter and error message from catch block*/);
return response;
}
}
}
Logging Function is as below
private void TransactionRequest(string xmlObject, Guid? groupKey, string name)
{
//writing to DB
}
private void TransactionResponse(string xmlObject, Guid? groupKey, string name)
{
//writing to DB
}
Now my question here is, I have to write in all 30+ function to log request and response like above.
Can anybody help me to how I can improve above or need to redesign whole approach.
I've had great success with using PostSharp for logging in my code bases. In the context of WCF its similar to the IServiceBehavior approach suggested by Aleksey L in that it gives you "hooks" that execute before and after the method's execution in which you can add your logging. The benefit comes in that you can also use the PostSharp logging attribute outside the context of WCF call.
Related
I'm currently in the process of writing a UWP application. I'm using a WCF Service to talk to a Business Layer that contains EF to talk to the SQL Server database. It's all in the very early stages as I've never used UWP before.
I got the UWP to consume the WCF to return data from the DB. This was working fine when I returned a string. However, now that I want to return objects this is no longer working in the sense that UWP just receives a reference. No object is returned. When I run the WCF in debug mode, the object is returned and I can see all the fields with data etc.
Could one of you geniuses help me, as I'm stuck and don't know what to do.
Here is my code. My class in Business Layer
namespace Business.Models
{
[DataContract(IsReference = true)]
public class SystemUser
{
public tblSystemUser User { get; set; }
// public tblRole Role { get; set; }
}
}
WCF code:
namespace ActiveCareWCF
{
[ServiceContract]
public interface IUser
{
[OperationContract]
Task<SystemUser> DoLogin(string userName);
}
public class Service : IUser
{
public async Task<SystemUser> DoLogin(string userName)
{
SystemUser systemUser = new SystemUser();
userName = #"username";
try
{
ServiceCalls serviceCalls = new ServiceCalls();
systemUser = serviceCalls.AuthorizeUser(userName);
return systemUser --- **this is returning an object**;
}
catch (Exception ex)
{
throw ex;
}
}
}
The SVC file:
public class ActiveCareService : IUser
{
public async Task<SystemUser> DoLogin(string userName)
{
Service service = new Service();
var user = service.DoLogin(userName);
return user.Result;
}
}
And finally the call in UWP.
private async void Login_Click(object sender, RoutedEventArgs e)
{
ActiveCareService.UserClient client = new ActiveCareService.UserClient();
var userFromService = client.DoLoginAsync(#"username").Result;
await client.CloseAsync();
var dialog = new MessageDialog("Logged in as " + userFromService.FirstName); **This just returns a string of the type of object it is, not the actual object. This is what I'm struggling with.**
await dialog.ShowAsync();
Frame.Navigate(typeof(YourSites));
}
Thanks in advance.
I'm doing the same thing, for now my services always return JSON strings, it means must serialize in service and deserialize at uwp.
You must have the model of serialized classes both at service and UWP. It works pretty well.
At My service I have a full Model and at UWP app I create a reduced model that matches with my needs.
Hope this can help.
I have a curious problem with a WCF service I've not been able to solve.
When I call a specific method on my service, it simply does not return to the client until the binding times out, although it already has returned on the server and a return message has been sent to the client.
I'm using ChannelFactory<T> on the client side, and shared interfaces that are defined like so:
[ServiceContract]
interface IService {
[OperationContract] bool Upload(Guid id, string name, byte[] data);
[OperationContract] bool Unlock(Guid id);
}
[ServiceContract(Name = "IService")]
interface IServiceAsync : IService {
[OperationContract] Task<bool> UploadAsync(Guid id, string name, byte[] data);
[OperationContract] Task<bool> UnlockAsync(Guid id);
}
The IService interface is implemented by the server class, the IServiceAsync interface is only used on the client (and works automagically).
The server is implemented in a standalone console application using ServiceHost, the server class looks like this:
[ServiceBehavior(InstanceContextMode = Single, ConcurrencyMode = Multiple)]
static class Server : IService {
public bool Upload(Guid id, string name, byte[] data) { ... }
public bool Unlock(Guid id) { ... }
}
On the client side, I create a channel using a ChannelFactory<T> like this:
static IServiceAsync GetService() {
EndpointAddress endpoint = new EndpointAddress(/* some Uri */);
NetTcpBinding binding = /* NetTcpBinding without security */;
ChannelFactory<IServiceAsync> factory =
new ChannelFactory<IServiceAsync>(binding, endpoint);
factory.Open();
IServiceAsync proxy = factory.CreateChannel();
((IServiceChannel)proxy).Open();
return proxy;
}
In my scenario, I then upload some files to the server, an operation that can be canceled by the user at any time. The code for the upload looks something like this:
static async void UseService(IServiceAsync proxy) {
try {
byte[] buffer;
do {
cancellationToken.ThrowIfCancellationRequested();
buffer = GetBytes();
bool uploaded = await proxy.UploadAsync(id, name, buffer);
} while(buffer.Length > 0);
((IClientChannel)proxy).Close();
}
catch (Exception ex) {
try {
proxy.Unlock(id);
}
catch {
// Connection may have failed
}
throw;
}
}
Now when the upload finishes everything works fine, but when the upload is canceled, and cancellationToken.ThrowIfCancellationRequested() throws an exception, I want to unlock the server.
So I call proxy.Unlock(id), which gets called on the server, returns there (confirmed by writing to the console immediately before return true; on the server), but does not return on the client side until the binding times out.
I looked at the network traffic once and confirmed that there is actually a return message being sent to the client. (I don't actually know whether proxy.Unlock(id) just returns or throws a CommunicationException, i suspect the second one.)
TL;DR: A WCF method does not return on the client side although it already returned on the server side, other methods work fine.
So, in case you're still here after that wall of text: what is wrong here?
How can I debug or solve this?
If you need any more information please let me know.
Update:
Thanks to Daniel's comment I did some tracing and managed to reproduce the problem on a small scale.
The problem only seems to happen when ConfigureAwait(false) is used when awaiting async WCF methods, an exception is thrown, and there is no context switch before the next call to a WCF method. I uploaded a small test project on GitHub.
Could this be a bug in the automagically implemented async methods in the WCF proxy?
I am creating an application that consumes a SOAP web service in C#. I generated a proxy class for the web service WSDL using the svcutil tool.
I added the proxy class to my code and I am using it to make calls to the web service and get results asynchrounsly.
Everything works pretty fine when the client has an Internet access. However, if I run attempt to access while the application doesn't have Internet access it crashes raising the following exception:
An exception of type 'System.ServiceModel.EndpointNotFoundException' occurred in
System.ServiceModel.Internals.dll but was not handled in user code
I am trying to catch this exception to prevent the application from crashing and provide the user with a more friendly error message, However, since I am doing async web calls, simply surrounding the web service calls by a try- catch does not help.
According to the exception details it happens in the End_FunctionName function that is defined inside the auto-generated proxy file.
Any tips about how to be able to gracefully handle this exception ?
Its pretty difficult to know exactly what is happening; however, I'm going to assume you have a web service like such
[ServiceContract]
public interface IMyService
{
[OperationContract]
String Hello(String Name);
[OperationContract]
Person GetPerson();
}
You probably have a proxy like this :
public class MyPipeClient : IMyService, IDisposable
{
ChannelFactory<IMyService> myServiceFactory;
public MyPipeClient()
{
//This is likely where your culprit will be.
myServiceFactory = new ChannelFactory<IMyService>(new NetNamedPipeBinding(), new EndpointAddress(Constants.myPipeService + #"/" + Constants.myPipeServiceName));
}
public String Hello(String Name)
{
//But this is where you will get the exception
return myServiceFactory.CreateChannel().Hello(Name);
}
public Person GetPerson()
{
return myServiceFactory.CreateChannel().GetPerson();
}
public void Dispose()
{
((IDisposable)myServiceFactory).Dispose();
}
}
If you have an error connecting you will get it not when you try to connect to the channel factory but when you actually try to call a function.
To fix this problem, you can put a try catch around every single function call and handle async calls manually.
Conversely, you can have a function like init() that is called synchronously every single time you instantiate a connection. This way you know that if that call connects that you have a connection.
If you are at risk of a connection dropping at any time I advise you go with the former option.
Anyway here is an example of how you'd fix it:
public class MyPipeClient : IMyService, IDisposable
{
ChannelFactory<IMyService> myServiceFactory;
public MyPipeClient()
{
myServiceFactory = new ChannelFactory<IMyService>(new NetNamedPipeBinding(), new EndpointAddress(Constants.myPipeService + #"/" + Constants.myPipeServiceName + 2) );
}
public String Hello(String Name)
{
try
{
return Channel.Hello(Name);
}
catch
{
return String.Empty;
}
}
public Person GetPerson()
{
try
{
return Channel.GetPerson();
}
catch
{
return null;
}
}
public Task<Person> GetPersonAsync()
{
return new Task<Person>(()=> GetPerson());
}
public Task<String> HelloAsync(String Name)
{
return new Task<String>(()=> Hello(Name));
}
public void Dispose()
{
myServiceFactory.Close();
}
public IMyService Channel
{
get
{
return myServiceFactory.CreateChannel();
}
}
}
I uploaded the source I wrote so that you could download the full source. You can get it here : https://github.com/Aelphaeis/MyWcfPipeExample
PS : This Repository throws the exception you are getting. In order to remove it just go to MyPipeClient and remove the + 2 in the constructor.
If you are using a Duplex, Consider using this repository:
https://github.com/Aelphaeis/MyWcfDuplexPipeExample
I am trying to figure out the best solution for getting error messages in between my service layer and WebApi controllers.
I have a class ModelStateDictionaryWrapper that implements an interface IValidationDictionary
ModelStateDictionaryWrapper
public class ModelStateDictionaryWrapper : IValidationDictionary
{
private readonly ModelStateDictionary modelStateDictionary;
public bool IsValid
{
get
{
return this.modelStateDictionary.IsValid;
}
}
public ModelStateDictionaryWrapper(ModelStateDictionary modelStateDictionary)
{
Enforce.ArgumentNotNull(modelStateDictionary, "modelStateDictionary");
this.modelStateDictionary = modelStateDictionary;
}
public void AddError(string key, string message)
{
this.modelStateDictionary.AddModelError(key, message);
}
}
IValidationDictionary
public interface IValidationDictionary
{
bool IsValid { get; }
void AddError(string key, string message);
}
In my api controller, I am doing this:
public class CategoryController : ControllerBase<ICategoryService>
{
private ICategoryService categoryService;
public CategoryController(ICategoryService categoryService)
{
this.categoryService = categoryService;
this.categoryService.ValidationDictionary =
new ModelStateDictionaryWrapper(this.ModelState);
}
public IEnumerable<CategoryViewModel> Get()
{
return Mapper.Map<CategoryViewModel[]>(this.Service.GetCategories());
}
}
The problem I have with this is I am making a new ModelStateDictionaryWrapper in the constructor of the service and I dont like that.
So I was thinking of changing this to take a factory like so:
public interface IModelStateWrapperFactory
{
IValidationDictionary GetModelStateWrapper(ModelStateDictionary modelStateDictionary);
}
public class ModelStateWrapperFactory : IModelStateWrapperFactory
{
public IValidationDictionary GetModelStateWrapper(
ModelStateDictionary modelStateDictionary)
{
return new ModelStateDictionaryWrapper(modelStateDictionary);
}
}
And then the api controller would look like this (constructor):
public CategoryController(ICategoryService categoryService,
IModelStateWrapperFactory modelStateWrapperFactory)
{
this.categoryService = categoryService;
this.categoryService.ValidationDictionary =
modelStateWrapperFactory.GetModelStateWrapper(this.ModelState);
}
I think I have removed the tight coupling. Does this look like a good solution?
Yes,
You have broken the dependencies between the classes, so you can mock the services during Unit Testing.
I don't know if you have used data annotations and a validation filter or not yet. If not, I would suggest you use them. More details from here http://www.asp.net/web-api/overview/formats-and-model-binding/model-validation-in-aspnet-web-api
An even better approach would be to completely remove this part out of the controller. It should be moved out of the controller, because:
This is effectively a cross-cutting concern and your controller should not be concerned with it; you are violating the Single Responsibility Principle.
Most (if not all) of your controllers will need this construct, which means that you have to repeat it all over the place, making it easy to forget it at some places; you are violating the Don't Repeat Yourself (DRY) principle.
This construct is only possible in the case that the class that needs validation is directly injected into the controller, which might not always be the case. Sometimes you'll need to do validation deeper down the object graph, or you might want to wrap the service with a decorator or interceptor, rendering this approach useless -or at least- extremely troublesome.
There are several solutions to this approach. The first that comes to my mind is to move the setting of the ModelState up, out of the CategoryController's constructor, for instance:
public IHttpController Create(HttpRequestMessage request,
HttpControllerDescriptor descriptor, Type type)
{
var wrapper = new ModelStateDictionaryWrapper();
var controller = new CategoryController(new CategoryService(wrapper));
wrapper.ModelState = controller.ModelState;
return controller;
}
Another -completely different- approach is to to not use the ModelState property at all, but to let your business layer throw specific validation exceptions and catch them higher up the call stack and transform them to Web API status codes.
Throwing exceptions would be a much better approach for the business layer, since this prevents validation errors to go unnoticed. Besides, a design where you fill a dictionary with validation errors is related to Web API and MVC, and is not something that your business layer should be concerned with.
You can do the following in your controller when your BL throws validation exceptions:
public class CategoryController : ControllerBase<ICategoryService>
{
private ICategoryService categoryService;
public CategoryController(ICategoryService categoryService)
{
this.categoryService = categoryService;
}
public HttpResponseMessage Update(CategoryViewModel model)
{
try
{
this.categoryService.Update(model.Category);
}
catch (ValidationException ex)
{
return WebApiValidationHelper.ToResponseCode(ex);
}
}
}
Downside here is of course that your try-catch statements with the calls to the WebApiValidationHelper.ToResponseCode will be duplicated in all your controllers; you'll be violating DRY.
So what you can do instead is extract this code into an DelegatingHandler. My preference would always be to use decorators, but unfortunately Web API makes it impossible to decorate ApiControllers, due to a quirk in its design. So you can inject the following DelegatingHandler into the Web API pipeline:
public class ValidationDelegationHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
try
{
return await base.SendAsync(request, cancellationToken);
}
catch (ValidationException ex)
{
return WebApiValidationHelper.ToResponseCode(ex);
}
}
}
This handler can be injected as follows:
config.MessageHandlers.Add(new ValidationDelegationHandler());
What would be a better approach when providing a wcf client with the call result.
1. Wrapping the result in an object
public enum DefinedResult : short {
Success = 0,
TimeOut = 1,
ServerFailure = 2,
UserNotFount = 3,
Uknown = 4,
//etc.
}
[DataContract]
public class ServiceResult {
readonly DefinedResults dResult;
public ServiceResult(DefinedResult result) {
this.dResult = result;
}
[DataMember]
public bool IsSuccess
{
get {return this.dResult == DefinedResult.Success;}
}
}
//Client:
WcfClient client = new WcfClient();
ServiceResult result = client.DoWork();
2. Throwing a custom Exception:
[Serializable]
public UserNotFoundException: Exception {
public UserNotFoundException(string message): base(message) {}
}
//client:
WcfClient client = new WcfClient();
try {
result = client.DoWork();
}
catch(FaultException<ExceptionDetail> ex) {
switch(ex.Detail.Type)
{
case "MyCompany.Framework.Exceptions.UserNotFound":
//handle
break;
case "MyCompany.Framework.Exceptions.ServerError":
//handle
break;
}
}
Now, the client can be another .net process (server side) or the same service can be called by java script, hence the question - which one of these (or may be there is something better) is a better approach to let the client know of what happened with the call?
First of all, it depends: if you want to return a condition which is not exceptional, then use a result value. Otherwise, use exceptions. In WCF, it goes like this:
Create a custom exception class:
[DataContract]
class MyException : FaultException<mydetails>
Define that your service throws it:
[FaultContract(...)]
void mymethod()...
throw MyException in your service method
Then you can catch your exception in the service method like catch FaultException<mydetails>
This is the nicest way there is.
FaultExceptions are swallowed by WebHttpBinding (required for JSON/REST services). In this case, if you want to provide detailed infos to your client, Option 1 is better.
If JSON is not in the way, I would recommend Option 2.