Can Silverlight WCF client read exceptions from an ASMX web service? - wcf

I've seen no need to upgrade my services to WCF, but I have been using WCF clients for some time to access ASMX services from .NET 3.5 ASP.NET. I figured eventually I'd hit a wall in this mismatch and I just did - but with Silverlight.
When using Silverlight to access ASMX web services I get an error like this in a popup :
An exception occurred during the
operation, making the result invalid.
Check InnerException for exception
details.
If I'm debugging I get this error :
The remote server returned an error: NotFound.
If I look in Fiddler the exception/fault is there just fine :
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body><soap:Fault>
<faultcode>soap:Server</faultcode>
<faultstring>Server was unable to process request. ---> ID does not match</faultstring>
<detail /></soap:Fault></soap:Body></soap:Envelope>
How do I actually get to this exception in the Silverlight client.
I need the error to be accessible at runtime with no fiddler and no debugger.
There is a property includeexceptiondetailinfaults that belongs in <behaviors> in the web.config - but this is for server side only as far as I can tell.
Am I correct in assuming that I will need to convert my asmx to svc to be able to get actual exception details in the silverlight client?

If you're happy to wrap the asmx SOAP request in your own IHttpHandler, you can force-feed a Response.StatusCode = 200 after the System.Web.Script.Services.ScriptHandlerFactory does it's work. Here's a sample;
static void ProcessService(HttpContext context)
{
//
// I'm also using this to fake/hide the path of my asmx so that
// domain.com/xml becomes the service end-point..
//
string asmx = "/Services/Some.Service.asmx";
string method = context.Request.Path.Substring("/xml".Length);
//
// ScriptHandlerFactory and friends are sealed so have to use reflection..
//
IHttpHandlerFactory fact = (IHttpHandlerFactory)Activator.CreateInstance(Type.GetType("System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions"));
Type vpt = Type.GetType("System.Web.VirtualPath, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
System.Reflection.MethodInfo mi = vpt.GetMethod("Create", new Type[] { typeof(string) });
object vp = mi.Invoke(null, new object[] { context.Request.Path });
System.Reflection.FieldInfo fi = context.Request.GetType().GetField("_pathInfo", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
System.Reflection.FieldInfo _virtualPath = vpt.GetField("_virtualPath", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
_virtualPath.SetValue(vp, method);
fi.SetValue(context.Request, vp);
IHttpHandler handler = fact.GetHandler(context, context.Request.RequestType, asmx, context.Server.MapPath(asmx));
try
{
// This will trap your asmx Exception and output 500 status and soap fault
handler.ProcessRequest(context);
// force 200 status for Silverlight to receive fault code
context.Response.StatusCode = 200;
context.ApplicationInstance.CompleteRequest();
}
finally
{
fact.ReleaseHandler(handler);
}
}

No client ever gets exceptions from web services. Web services don't send exceptions - they send faults.
The details of the fault are contained in the <detail/> element of the fault message. some platforms, including WCF, parse this information in order to translate from the fault to a platform-specific exception.
Since there is no information in the <detail/> element, no translation is likely to occur.

Related

Xamarin.Forms Add Connected Service on WCF only generated async method

I just begun to do Xamarin.Forms with .Net Standard 2.0 (PCL) project. I'm trying to consume my WCF web service but never got it successfully done.
I have created a simple WCF as below
[ServiceContract]
public interface IWcfConnection
{
[OperationContract]
string GetHelloWorld();
}
the implementation as below
public class WcfConnection : IWcfConnection
{
public string GetHelloWorld()
{
return "Hello World";
}
}
It's a very simple WCF, when I go to my Xamarin.Forms and right click on the "Connected Service", there is no "Add Web Service", but only "Add Connected Service", so I selected that as below
Then select "Microsoft WCF Web Service Service Provider"
Select the option as below (I untick everything because if I add more than 1 service, it will crash)
When I look into the reference.cs created, there is only async method created.
public System.Threading.Tasks.Task<string> GetHelloWorldAsync()
{
return base.Channel.GetHelloWorldAsync();
}
1) May I know why only async is created? Is it for .net standard and core, only async services will be created? As I read somewhere.
2) If so, how do I consume the web service?
In my xaml.cs file, I did the following,
WcfConnectionService.WcfConnectionClient client = new WcfConnectionService.WcfConnectionClient(new WcfConnectionService.WcfConnectionClient.EndpointConfiguration());
string abc = client.GetHelloWorldAsync().GetAwaiter().GetResult();
But I'm getting error and unable to work accordingly. Anybody got any idea?
Unhandled Exception:
System.ServiceModel.FaultException`1[[System.ServiceModel.ExceptionDetail, System.ServiceModel, Version=2.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]: Error in deserializing body of request message for operation 'GetHelloWorld'. OperationFormatter encountered an invalid Message body. Expected to find node type 'Element' with name 'GetHelloWorld' and namespace 'http://tempuri.org/'. Found node type 'Element' with name 'GetHelloWorldAsync' and namespace 'http://tempuri.org/'
At the moment Xamarin apps aren't compatible with the Task-based asynchronous WCF proxy methods that the WCF Web Service Reference connected service provider generates for .NET Standard projects (bugzilla.xamarin.com Bug 51959).
Generate an older compatible style of WCF proxy methods via checked "Generate Synchronous Operations" checkbox on Configure WCF Web Service Reference screen:
Consume the web service:
KimlikServiceReference.KPSPublicSoapClient soapClient = new KimlikServiceReference.KPSPublicSoapClient(KimlikServiceReference.KPSPublicSoapClient.EndpointConfiguration.KPSPublicSoap);
//KimlikServiceReference.TCKimlikNoDogrulaResponse response = soapClient.TCKimlikNoDogrulaAsync(TCKimlikNo, Ad, Soyad, DogumYili).Result;
bool result = soapClient.TCKimlikNoDogrula(TCKimlikNo, Ad, Soyad, DogumYili);

500 Internal Server Error on a self hosted WCF Service

I am attempting to develop a new WCF service that is hosted using the ServiceHost object. I am able to get the console application to start and I can see that it is binding to port 80 via netstat. Using WireShark I am also able to see that the client is able to connect to that port and send over the data. I had a problem early on with the amount of data that is being sent in the SOAP message from the client, but was able to resolve that issue by setting the max receive size on the binding. The HTTP 500 error that I am getting is:
The message with Action '' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).
The following is my WCF code and my service code.
public class MyWCFService
{
private ServiceHost _selfHost;
public void Start()
{
Uri baseAddress = new Uri(#"http://192.168.1.10");
this._selfHost = new ServiceHost(typeof(MyServiceImpl), baseAddress);
try {
WebHttpBinding binding = new WebHttpBinding();
binding.MaxBufferSize = 524288;
binding.MaxReceivedMessageSize = 524288;
this._selfHost.AddServiceEndpoint(typeof(IMyServiceContract), binding, "MyService");
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
this._selfHost.Description.Behaviors.Add(smb);
this._selfHost.Open();
}
catch ( CommunicationException ce ) {
this._selfHost.Abort();
}
}
public void Stop()
{
this._selfHost.Close();
}
}
The following is my service contract. It is fairly simple and only has a single Operation. It is expected that it will be called upon the receipt of a SOAP based message.
[ServiceContract(Namespace = "http://www.exampe.com")]
public interface IMyServiceContract
{
[OperationContract (Action="http://www.example.com/ReportData", ReplyAction="*")]
string ReportData( string strReport );
}
The following the my implementation of the service contract
class MyServiceImpl : IMyServiceContract
{
public string ReportData( string strReport )
{
return "ok";
}
}
Here is what I am getting from my client (the strReport was very long so I excluded it)
POST /MyService HTTP/1.1
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://www.example.com/ReportData"
Host: 192.168.1.10
Content-Length: 233615
Expect: 100-continue
Connection: Keep-Alive
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<ReportData xmlns="http://www.example.com/">
<strReport>
........
</strReport>
</ReportData>
</soap:Body>
</soap:Envelope>
Any help resolving this issue would be greatly appreciated.
Regards,
Richard
Do you want your service to be a SOAP service or a REST service?
On the service side, it is configured to be a REST services (because you are using WebHttpBinding). However, the request from your client is a SOAP request. If your client is a WCF client, it is probably using wsHttpBinding or basicHttpBinding. Both of these are for SOAP.
You can either:
Change your service to use basicHttpBinding or wsHttpBindding to match your client (if you want to use SOAP), or
Change your client to use webHttpBinding (if you want to use REST). This will need more changes because your operation contract is not properly Attributed for REST. And anyway, WCF is not a good option for REST. The ASP.Net Web API is much simpler and better supported.
Also
the Action specified in your operation contract should be just ReportData rather than the namespace qualified version. You may not need it at all in fact.
you can remove the ReplyAction (or specify a proper value if your client needs it)
Generally, you do not need to specify these. I'm not an expert on the innards of SOAP but I believe that WCF will specify these values based on the method name if you don't specify them. Uniqueness of method names in .Net will ensure that the action/replyaction are unique in that case.
With these changes in place It Works On My Machine (TM)

The underlying connection was closed: An unexpected error occurred on a receive. while Using WCF

I am using mvc4 as my web application which inherits a WCF service i have an Entity framework and used Code first for database Now, Entity layer is inherited to both MVC as well as to WCF but Data Access layer is only inherited to the WCF, Now when ever i call the WCF method from my controller the method is called nicely and the method works fine into the WCF and returns the expected result but when it returns result to the MVC application it throws an exception of "The underlying connection was closed: An unexpected error occurred on a receive." can anyone please help me out, following is the code respectively:-
for Controller class
public ActionResult CustomerSearch()
{
APIServiceDaman.Customer ObjTestEn = new APIServiceDaman.Customer();
using (Objjj = new APIServiceDaman.Service1())
{
var ObjTestEn2 = Objjj.GetUserDetails(1, true);
}
return View(ObjTestEn);
}
for WCF:-
public X.Entities.Customer GetUserDetails(int CustomerID)
{
X.Entities.Customer objtest = new X.Entities.Customer();
using (ObjCustomerEvidence = new CustomerManager())
{
objtest = ObjCustomerEvidence.GetCustomerByID(CustomerID);
}
return objtest;
}
for DataAccess Layer:-
public Entities.Customer GetCustomerByID(int ID)
{
return DBContext.Customer.Where(c => c.ID == ID).FirstOrDefault();
}
First of all check your web.config setting for executionTimeout and maxRequestLength on both side WCF and your MVC4 client. for more information on this please refer this below link there is a good answer given by jlchereau, follow this steps and try to check it out again, it might help you out. also try to enable WCF tracing (Tracing) and find out the root of exception it will help you a lot to resolve your issue.
http://velodocaddin.codeplex.com/discussions/40792

Call a WCF Service using just manual code (no config or autogen code)

I am loosely following the method in WCF The Right Way ... The Manual Way to setup my WCF Service.
I have a manually generated proxy class that looks like this:
// Setup a client so we can call our web services.
public class EmployeeClient :IEmployeeService
{
private readonly IEmployeeService EmployeeChannel;
public EmployeeClient(Binding binding, string address)
{
var endpointAddress = new EndpointAddress(address);
EmployeeChannel = new ChannelFactory<IEmployeeService>
(binding, endpointAddress).CreateChannel();
}
public EmployeeResponse SaveOrUpdateEmployee(EmployeeContract employee)
{
return EmployeeChannel.SaveOrUpdateEmployee(employee);
}
}
I then want to call some of these services. But I don't want to use any config files (I am setting up some integration tests and I don't want more dependencies than needed.)
I am currently trying to call them like this:
serviceHost = SelfServiceHost.StartupService();
employeeClient = new EmployeeClient(new BasicHttpBinding(),
SelfServiceHost.StartUpUrl);
EmployeeResponse employeeResponse = employeeClient.SaveOrUpdateEmployee(emp);
When I do that I am getting this exception:
System.ServiceModel.ProtocolException: Content Type text/xml; charset=utf-8 was not supported by service http://localhost:8090/EmployeeService. The client and service bindings may be mismatched. ---> System.Net.WebException: The remote server returned an error: (415) Cannot process the message because the content type 'text/xml; charset=utf-8' was not the expected type 'application/soap+xml; charset=utf-8'..
What do I need to do to get a call to my service working with code only?
From what you dessribe the binding is not configured in a compatible way.
I suspect that the WCF host has wsHttpBinding and your client-side has BasicHttpBinding or similar...
see http://social.msdn.microsoft.com/forums/en-US/wcf/thread/f29cd9c8-3c89-43d2-92ae-d2a270ab86b9/

Trying to follow WCF delegation example on MSDN but keep getting "impersonation level" exception

Near the bottom of this article (MSDN) in a section entitled "The following code example demonstrates how to use delegation." where MSDN shows an example of how to perform delegation. I have tried to take this example and apply it to my code. In my situation, I have a client app (WCFTestClient), a middle service and a back end service. The goal is is to have the client execute a WCF exposed method on the middle service which in turn calls another method on the back end service. I'm trying to get the identity of the execution on both middle service and back end service to be that of the user executing the client:
Client ----> Middle Service ----> Back End Service.
Here is the exception that occurs on the "channel.PreparePolicy" invocation:
Could not load file or assembly 'System.Transactions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' or one of its dependencies. Either a required impersonation level was not provided, or the provided impersonation level is invalid. (Exception from HRESULT: 0x80070542)
Here is my code, taken most directly from the example. I did add one line that differs from the MSDN example in my attempt to debug channelFactory.Credentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Delegation;
but to no effect.
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
public void PreparePolicy(string requestGuid, string policyName, ulong version)
{
WindowsIdentity callerWindowsIdentity = ServiceSecurityContext.Current.WindowsIdentity;
if (callerWindowsIdentity == null)
{
throw new InvalidOperationException
("The caller cannot be mapped to a Windows identity.");
}
using (callerWindowsIdentity.Impersonate())
{
NetTcpBinding binding = new NetTcpBinding();
binding.Security.Mode = SecurityMode.Message;
Uri uri = new Uri(String.Format("net.tcp://{0}:{1}/App", "10.192.12.159", 8080));
EndpointAddress backendServiceAddress = new EndpointAddress(uri);
ChannelFactory<Service> channelFactory = new ChannelFactory<Service>(binding, backendServiceAddress);
channelFactory.Credentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Delegation;
Service channel = channelFactory.CreateChannel();
channel.PreparePolicy("alkdjf", policyName, version);
}
}
I was using the WCFTestClient as my client in this scenario. Turns out its not enabled to allow delegation. I wrote my own client and enabled it for delegation and everything worked fine.