WCF Service fails when accessing host registry - c#

I've been working on a wrapper for an API that will let me access it via a web service. The wrapper is a WCF service that I'm using to interface between the API and an asmx.
API---WCF---Webservice
Currently, I can get the API to work with the wrapper and the wrapper to communicate with the web service. However, any calls I make that originate from the web service to the API fail. The line that causes the failure is one that accesses a registry key on the host. My guess is that this is somehow permission related, but I'm new to C# and web services so I don't know for sure.
If it is permission related, where/how can I give the client permission to access the host's registry?
WFC code:
public class IRClass
{
...
public string init()
{
string result = "THE SERVICE IS WORKING BORK BORK\n";
int handle = 1234;
double retVal = -1;
Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(#"SOFTWARE\Rand McNally\DispatchAssistant\StandAlone\Install");
\\^^^ THIS RETURNS NULL WHEN CALLED BY A CLIENT ^^^
if (key != null)
{
string sbDARouterFilePath = key.GetValue("DaRouterPath").ToString();
string sbDADataFilePath = key.GetValue("DaDataPath").ToString();
string sbRouterFilePath = key.GetValue("RoutePath").ToString();
string sbMapFilePath = key.GetValue("MapPath").ToString();
string sbAdminFilePath = key.GetValue("AdminPath").ToString();
string sbDataFilePath = key.GetValue("DataPath").ToString();
try
{
RECode = irLib.irSAInitialize(sbDARouterFilePath, sbDADataFilePath, sbRouterFilePath, sbMapFilePath, sbAdminFilePath, sbDataFilePath);
}
catch (Exception e)
{
throw new Exception("irSAInitialize call failed in IntelliRouteLib.IRApi\n + e.Message);
}
result += "Key: " + key.ToString() + " \n";
}
else
{
result += "KEY IS NULL\n"; \\THIS SHOULDN'T HAPPEN
}
...
return result;//return RECode.ToString();
}
}
WCF App.Config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" />
</system.web>
<system.serviceModel>
<services>
<service name="RmWcfServiceLibrary.RMService">
<host>
<baseAddresses>
<add baseAddress = "http://localhost:8733/Design_Time_Addresses/RmWcfServiceLibrary/RMService/" />
</baseAddresses>
</host>
<!-- Service Endpoints -->
<endpoint address="" binding="basicHttpBinding" contract="RmWcfServiceLibrary.IIntRoute">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<!-- Metadata Endpoints -->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<system.diagnostics>
<trace autoflush="true" />
<sources>
<source name="System.ServiceModel"
switchValue="Information, ActivityTracing"
propagateActivity="true">
<listeners>
<add name="sdt"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData= "SdrConfigExample.e2e" />
</listeners>
</source>
</sources>
</system.diagnostics>
</configuration>
WebService Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using RMWebService.RmWcf;
namespace RMWebService
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class WebService1 : System.Web.Services.WebService
{
[WebMethod]
public string Intelliroute()
{
IntRouteClient client = new IntRouteClient();
string output = client.IRinit();
client.Close();
return output;
}
}
}
Thanks

Related

WCF with basic authentification (Remote Server returned an error: 404 Not found)

I am trying to access my wcf (http protocol using port 26880) service externally (deployed on IIS) after setting it up with a Basic Authentication Module, but it throws the following error:
The remote server returned an error: (404) Not Found.
What I have tried so far:
Removed the basic authentication and checked that the service can be accessed both internally and externally and that works.
Checked that the service actually receives the header authorization and the user is logged in.(This works)
Added the following line in my web.config file:
<modules runAllManagedModulesForAllRequests="true">
after adding my BasicAuthenticationModule and still no luck.
Went in IIS and made sure that BasicAuthentication is enabled.
Enabled trace logging and apparently I cannot see any errors besides the fact that it looks at this address: http://localhost/ResponseService
when in fact it should be http://localhost:26880/ResponseService
I have googled and tried every possible solution that I found related to my error and no results so far.
This is my web.config file:
<configuration>
<appSettings/>
<system.web>
<compilation debug="true" targetFramework="4.5"/>
<httpRuntime maxRequestLength="51200" enable="true" executionTimeout="60000"/>
<customErrors mode="Off"/>
<authentication mode="None"/>
<pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID"/>
</system.web>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" minFreeMemoryPercentageToActivateService="1" multipleSiteBindingsEnabled="true"/>
<services>
<service behaviorConfiguration="Default" name="dcs_response_handler.ResponseService">
<host>
<baseAddresses>
<add baseAddress="http://'external ip':26880/DcsResponse/"/>
</baseAddresses>
</host>
<endpoint name="webHttpBinding" contract="dcs_response_handler.IResponseService" binding="webHttpBinding" address="" bindingConfiguration="webHttpBinding" behaviorConfiguration="webBehavior"/>
<endpoint name="mexHttpBinding" address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<protocolMapping>
<add binding="webHttpBinding" scheme="http"/>
</protocolMapping>
<behaviors>
<serviceBehaviors>
<behavior name="Default">
<useRequestHeadersForMetadataAddress/>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
<behavior>
<useRequestHeadersForMetadataAddress/>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="webHttpBinding"
transferMode="Streamed">
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
</security>
</binding>
</webHttpBinding>
</bindings>
</system.serviceModel>
<system.webServer>
<directoryBrowse enabled="true"/>
<validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="true">
<remove name="BasicAuthenticationModule"/>
<remove name="UrlRoutingModule-4.0" />
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />
<add name="BasicAuthenticationModule" type="dcs_response_handler.BasicAuthenticationModule" preCondition=""/>
</modules>
<handlers>
<remove name="svc-Integrated-4.0" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*" verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
<security>
<authentication>
<windowsAuthentication enabled="false"/>
<anonymousAuthentication enabled="false"/>
</authentication>
<requestFiltering>
<requestLimits maxAllowedContentLength="32000000" />
</requestFiltering>
</security>
</system.webServer>
<system.diagnostics>
<sources>
<source name="System.ServiceModel"
switchValue="Information, ActivityTracing"
propagateActivity="true" >
<listeners>
<add name="xml"/>
</listeners>
</source>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add name="xml"/>
</listeners>
</source>
<source name="myUserTraceSource"
switchValue="Information, ActivityTracing">
<listeners>
<add name="xml"/>
</listeners>
</source>
</sources>
<sharedListeners>
<add name="xml"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData="Error.svclog" />
</sharedListeners>
</system.diagnostics>
</configuration>
And my BasicAuthenticationModule along with BasicAuthenticationProvider (source Custom Basic Authentication):
public class BasicAuthenticationModule : IHttpModule
{
public void Dispose()
{
throw new NotImplementedException();
}
public void Init(HttpApplication context)
{
context.AuthenticateRequest
+= new EventHandler(context_AuthenticateRequest);
}
void context_AuthenticateRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
if (!BasicAuthenticationProvider.Authenticate(application.Context))
{
application.Context.Response.Status = "401 Unauthorized";
application.Context.Response.StatusCode = 401;
application.Context.Response.AddHeader("WWW - Authenticate", "Basic");
application.CompleteRequest();
}
}
}
public class BasicAuthenticationProvider
{
public static bool Authenticate(HttpContext context)
{
if (!HttpContext.Current.Request.Headers.AllKeys.Contains("Authorization"))
{
return false;
}
string authHeader = HttpContext.Current.Request.Headers["Authorization"];
IPrincipal principal;
if (TryGetPrincipal(authHeader, out principal))
{
HttpContext.Current.User = principal;
return true;
}
return false;
}
private static bool TryGetPrincipal(string authHeader, out IPrincipal principal)
{
var creds = ParseAuthHeader(authHeader);
if (creds != null && TryGetPrincipal(creds, out principal))
{
return true;
}
else
{
principal = null;
return false;
}
}
private static string[] ParseAuthHeader(string authHeader)
{
if (
authHeader == null ||
authHeader.Length == 0 ||
!authHeader.StartsWith("Basic")
)
{
return null;
}
string base64Credentials = authHeader.Substring(6);
string[] credentials = Encoding.ASCII.GetString(
Convert.FromBase64String(base64Credentials)
).Split(new char[] { ':' });
if (credentials.Length != 2 ||
string.IsNullOrEmpty(credentials[0]) ||
string.IsNullOrEmpty(credentials[1])
)
{
return null;
}
// Okay this is the credentials
return credentials;
}
private static bool TryGetPrincipal(string[] creds, out IPrincipal principal)
{
if (ValidateLogin.IsLoginValid(new System.Net.NetworkCredential(creds[0], creds[1])))
{
principal = new GenericPrincipal(
new GenericIdentity(creds[0]),
new string[] { "Administrator", "Users" }
);
return true;
}
else
{
principal = null;
return false;
}
}
}
And this is my client:
public static void ServiceClientTest()
{
HttpWebRequest req = null;
HttpWebResponse resp = null;
string SampleXml = string.Empty;
string baseAddress = "http://'external ip':26880/DcsResponse/XMLGate/inbound?System=84771500";
try
{
string strResult = string.Empty;
using (StreamReader readFile = new StreamReader(#"C:\Users\Alin\Desktop\testingXml.xml"))
{
SampleXml = readFile.ReadToEnd();
}
string postData = SampleXml.ToString();
byte[] data = Encoding.UTF8.GetBytes(postData);
string svcCredentials = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes("alin" + ":" + "Dcs1234"));
HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(baseAddress);
webrequest.Headers.Add("Authorization", "Basic " + svcCredentials);
webrequest.Method = "POST";
webrequest.ContentType = "text/xml";
webrequest.ContentLength = data.Length;
Stream newStream = webrequest.GetRequestStream();
newStream.Write(data, 0, data.Length);
newStream.Close();
HttpWebResponse webresponse = (HttpWebResponse)webrequest.GetResponse();
if (webresponse.StatusCode == HttpStatusCode.OK)
{
Stream stream = webresponse.GetResponseStream();
using (StreamReader reader = new StreamReader(stream))
{
Console.WriteLine(reader.ReadToEnd());
}
}
}
catch (WebException webEx)
{
Console.WriteLine("Web exception :" + webEx.Message);
}
catch (Exception ex)
{
Console.WriteLine("Exception :" + ex.Message);
}
}
Based on the error I am getting I'm assuming that it can't find a file or my web.config is not setup properly? Any new ideas?

WCF service streaming images

I'd like to make WCF service which can put image into stream.
I have next in config:
<service name="Images" behaviorConfiguration="ImagesBehavior">
<endpoint address="http://localhost:5523/Images.svc"
binding="basicHttpBinding" contract="Images" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:5523/Images" />
</baseAddresses>
</host>
</service>
<behavior name="ImagesBehavior">
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceMetadata httpGetEnabled="true" />
</behavior>
And code:
[OperationContract]
[WebGet(UriTemplate = "GetImage/{imageID}",
BodyStyle = WebMessageBodyStyle.Bare)]
public Stream GetImage(string imageID)
{
try
{
if (WebOperationContext.Current != null)
WebOperationContext.Current.OutgoingResponse.ContentType = "image/jpeg";
var ms = new MemoryStream(myImage);
return ms;
}
catch (Exception e)
{
if (WebOperationContext.Current != null)
WebOperationContext.Current.OutgoingResponse.ContentType = "text/xml";
Console.WriteLine("GetImage ERROR:" + e.Message + "\r\n" + e.StackTrace);
byte[] errorBytes = Encoding.UTF8.GetBytes("ERROR");
return new MemoryStream(errorBytes);
}
}
But when I'm trying this via browser like
http://localhost:5523/Images.svc/GetImage/imagecodeblabla
I've got
400 Bad Request
And when
http://localhost:5523/Images/GetImage/imagecodeblabla
405 Method Not Allowed
What's wrong?
Is your service SOAP or REST? It appears that you're using REST syntax (WebGetAttribute) but your binding is BasicHttpBinding (SOAP).
Try using WebHttpBinding instead and see how that goes!

Running wcf service without App.config doesn't work

I create simple wcf host in console application. It doesn't work and the exception make NO SENSE:/
The exception looks really wierd:
"ContractDescription 'IFooService' has zero operations; a contract
must have at least one operation."
because, here is the code and i I have an operation:
[ServiceContract]
public interface IFooService
{
[OperationContract]
void DoNothing();
[OperationContract]
int GetFoo(int i);
}
public class FooService : IFooService
{
public void DoNothing()
{
}
public int GetFoo(int i)
{
return i + 1;
}
}
class Program
{
static void Main(string[] args)
{
try
{
string address = "http://localhost:9003/FooService";
Uri addressBase = new Uri(address);
var svcHost = new ServiceHost(typeof(FooService), addressBase);
BasicHttpBinding bHttp = new BasicHttpBinding();
Type contractType = typeof(IFooService);
ContractDescription contractDescription = new ContractDescription(contractType.Name);
contractDescription.ProtectionLevel = ProtectionLevel.None;
contractDescription.ContractType = contractType;
contractDescription.ConfigurationName = contractType.FullName;
contractDescription.SessionMode = SessionMode.NotAllowed;
svcHost.AddServiceEndpoint(new ServiceEndpoint(contractDescription, bHttp, new EndpointAddress(address)));
svcHost.Open();
Console.WriteLine("\n\nService is Running as >> " + address);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.ReadKey();
}
}
This is basically entire code. App.config is left untouched:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
</configuration>
EDIT: A little clue, this way it works: I didn't change service or contract, but moved configuration to App.config, so changed only Main method:
App.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<system.serviceModel>
<services>
<service name="WcfDemos.ConsoleHost.FooService">
<endpoint address="http://localhost:9003/FooService" binding="basicHttpBinding"
contract="WcfDemos.ConsoleHost.IFooService" />
</service>
</services>
</system.serviceModel>
</configuration>
Main:
static void Main(string[] args)
{
try
{
string address = "http://localhost:9003/FooService";
Uri addressBase = new Uri(address);
var svcHost = new ServiceHost(typeof(FooService), addressBase);
svcHost.Open();
Console.WriteLine("\n\nService is Running as >> " + address);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.ReadKey();
}
Why do you need to use the ContractDescription? I suppose it looks for the settings in the configuration file.
You may do the following (use the AddServiceEndpoint method without ContractDescription):
static void Main(string[] args)
{
try
{
string address = "http://localhost:9003/FooService";
Uri addressBase = new Uri(address);
var svcHost = new ServiceHost(typeof(FooService), addressBase);
BasicHttpBinding bHttp = new BasicHttpBinding();
//Type contractType = typeof(IFooService);
//ContractDescription contractDescription = new ContractDescription(contractType.Name);
//contractDescription.ProtectionLevel = ProtectionLevel.None;
//contractDescription.ContractType = contractType;
//contractDescription.ConfigurationName = contractType.FullName;
//contractDescription.SessionMode = SessionMode.NotAllowed;
//svcHost.AddServiceEndpoint(new ServiceEndpoint(contractDescription, bHttp, new EndpointAddress(address)));
svcHost.AddServiceEndpoint(typeof(IFooService).ToString(), bHttp, address);
svcHost.Open();
Console.WriteLine("\n\nService is Running as >> " + address);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.ReadKey();
}
BTW here you may find some library for configuring your WCF services without app.config files: WCF NetTcpBinding Bootcamp
I believe you have to add an endpoint to the ServiceHost if you don't provide the endpoints in the config file. See the AddServiceEndpoint call:
Uri baseAddr = new Uri("http://localhost:8000/WCFService1");
ServiceHost localHost = new ServiceHost(typeof(CalculatorService), baseAddr);
try
{
localHost.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), "CalculatorService");
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
localHost.Description.Behaviors.Add(smb);
localHost.Open();
Console.WriteLine("Service initialized.");
Console.WriteLine("Press the ENTER key to terminate service.");
Console.WriteLine();
Console.ReadLine();
localHost.Close();
}
catch (CommunicationException ex)
{
Console.WriteLine("Oops! Exception: {0}", ex.Message);
localHost.Abort();
}
http://www.programminghelp.com/dotnet/wcf-creating-and-implementing-a-service-in-c/
The above comes from Microsoft example:
https://learn.microsoft.com/en-us/dotnet/framework/wcf/how-to-host-and-run-a-basic-wcf-service
which is a great place to start. Nonetheless ... it is still unclear what needs to be added in code to make the app.config content below redundant:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" />
</system.web>
<!-- When deploying the service library project, the content of the config file must be added to the host's
app.config file. System.Configuration does not support config files for libraries. -->
<system.serviceModel>
<services>
<service name="GettingStartedLib.CalculatorService">
<host>
<baseAddresses>
<add baseAddress = "http://localhost:8000/GettingStarted/CalculatorService" />
</baseAddresses>
</host>
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address="" binding="wsHttpBinding" contract="GettingStartedLib.ICalculator">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically.
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<!-- Metadata Endpoints -->
<!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. -->
<!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information,
set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>

How to use HTTPS with WCF SessionMode.Required - simplest possible example

UPDATE (8/7/2014) - The solution to this problem was that I needed to add a class that derived from "UserNamePasswordValidator" and register it in Web.Config.
I have created a simple test WCF service and test console client application (see below for code). I am using .NET 4.5.1. I have already searched for duplicates on StackOverflow (found similar posts here and here) - however I feel that the referenced posts are potentially outdated, and also feel that my post is more limited in scope.
OK now for the example:
The solution currently uses sessions (in ITestService.cs):
[ServiceContract(SessionMode = SessionMode.Required)]
... and uses wsHttpBinding (see below app.config and web.config).
When I deploy this to a server, I am successfully able to access it via a web browser using HTTPS like this: https://myserver.com/test/testservice.svc
However, when I change the endpoint in the client app.config from:
http://localhost:20616/TestService.svc/TestService.svc
to:
https://myserver.com/test/testservice.svc
and run the console application again, I receive the error: "The provided URI scheme 'https' is invalid; expected 'http'. Parameter name: via"
My question is, what is the minimum changes I need to make for this to work, without changing SessionMode.Required?
Here is the client console application code. Please be sure to change the App.Config value for "mycomputer\Matt" to the correct value for your machine.
Program.cs
using System;
namespace TestClient
{
class Program
{
static void Main(string[] args)
{
Console.Clear();
Console.WriteLine("Attempting to log in...");
try
{
TestServiceReference.TestServiceClient client = new TestServiceReference.TestServiceClient();
bool loginSuccess = client.LogIn("admin", "password");
if (loginSuccess)
{
Console.WriteLine("Successfully logged in.");
string secretMessage = client.GetSecretData();
Console.WriteLine("Retrieved secret message: " + secretMessage);
}
else
{
Console.WriteLine("Log in failed!");
}
}
catch (Exception exc)
{
Console.WriteLine("Exception occurred: " + exc.Message);
}
Console.WriteLine("Press ENTER to quit.");
Console.ReadLine();
}
}
}
App.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/>
</startup>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_ITestService"/>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://myserver.com/test/testservice.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ITestService" contract="TestServiceReference.ITestService" name="WSHttpBinding_ITestService">
<identity>
<userPrincipalName value="mycomputer\Matt"/>
</identity>
</endpoint>
<!--<endpoint address="http://localhost:20616/TestService.svc/TestService.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ITestService" contract="TestServiceReference.ITestService" name="WSHttpBinding_ITestService">
<identity>
<userPrincipalName value="mycomputer\Matt"/>
</identity>
</endpoint>-->
</client>
</system.serviceModel>
</configuration>
WCF Service code.
ITestService.cs:
using System.ServiceModel;
namespace WcfSessionsOverHttpsTest
{
[ServiceContract(SessionMode = SessionMode.Required)]
public interface ITestService
{
[OperationContract(IsInitiating = true)]
bool LogIn(string username, string password);
[OperationContract(IsInitiating = false, IsTerminating = true)]
bool LogOut();
[OperationContract(IsInitiating = false)]
string GetSecretData();
}
}
TestService.svc:
namespace WcfSessionsOverHttpsTest
{
public class TestService : ITestService
{
public bool IsAuthenticated { get; set; }
bool ITestService.LogIn(string username, string password)
{
if (username == "admin" && password == "password")
{
IsAuthenticated = true;
return true;
}
else
{
IsAuthenticated = false;
return false;
}
}
bool ITestService.LogOut()
{
IsAuthenticated = false;
return true;
}
string ITestService.GetSecretData()
{
if (!IsAuthenticated)
{
throw new System.Security.Authentication.AuthenticationException("User has not logged in.");
}
else
{
string secretMessage = "The Red Sox are going to win the World Series in 2016";
return secretMessage;
}
}
}
}
Web.config:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5.1"/>
<httpRuntime targetFramework="4.5"/>
</system.web>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttpEndpointBinding" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="WcfSessionsOverHttpsTest.TestService">
<endpoint address="/TestService.svc" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" contract="WcfSessionsOverHttpsTest.ITestService"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="wsHttpBinding" scheme="http"/>
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
Thanks in advance for any help!
Matt
The solution to this problem was that I needed to add a class that derived from "UserNamePasswordValidator" and register it in Web.Config.
public class CustomUserNameValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
return;
}
}
Web.config:
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpsGetEnabled="true" />
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="MyProgram.CustomUserNameValidator,MyProgram" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>

UNABLE to POST data to WCF from Android

I'm trying to send data to WCF service from an Android Application but somehow the service doesn't seems to be call through the android. I received a STATUSCODE value = 500 through adnroid in LOGCAT (which means the Internal Server Error) I go through the source code 100 times but didn't figure out the Bug. and almost checked all the posts related to my problem but still didn't get any solution.
HERE IS THS CODE
Android Code:
private class sendPostData extends AsyncTask<String, Void, String>
{
#Override
protected String doInBackground(String... params) {
// TODO Auto-generated method stub
HttpPost request = new HttpPost( LOGIN_SERVICE_URL + "/MyCar");
request.setHeader("Accept", "application/json");
request.setHeader("Content-type", "application/json");
JSONStringer getCarInfo;
try {
getCarInfo = new JSONStringer()
.object()
.key("myCar")
.object()
.key("Name").value(edt_carName.getText().toString())
.key("Make").value(edt_carMake.getText().toString())
.key("Model").value(edt_carModel.getText().toString())
.endObject()
.endObject();
StringEntity entity = new StringEntity(getCarInfo.toString());
request.setEntity(entity);
// Send request to WCF service
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpResponse response = httpClient.execute(request);
Log.d("WebInvoke", "Saving : " + response.getStatusLine().getStatusCode());
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String result) {
txt_verif.setText("Success");
}
}
everything is working fine in android code except calling the WCF service. I Debug the code several times and received statuscode = 500
HERE is the WCF Service
Service.cs
public class Service1 : IService1
{
public void UpdateMyCar(myCar myCar) {
string strConnectionString = ConfigurationManager.ConnectionStrings["Database1"].ConnectionString;
SqlConnection conn = new SqlConnection(strConnectionString);
conn.Open();
using (SqlCommand cmd = new SqlCommand("Insert into TestingTable (Name,Make,Model) Values (#Name,#Make,#Model)", conn)) {
cmd.Parameters.AddWithValue("#Name", myCar.Name);
cmd.Parameters.AddWithValue("#Make", myCar.Make);
cmd.Parameters.AddWithValue("#Model", myCar.Model);
int queryResult = cmd.ExecuteNonQuery();
} conn.Close();
}
LogCat
WebInvoke Saving : 500
IService1.svc
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebInvoke(
Method = "POST",
UriTemplate = "MyCar",
BodyStyle = WebMessageBodyStyle.WrappedRequest,
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json)]
void UpdateMyCar(myCar myCar);
}
[DataContract]
public class myCar
{
[DataMember(Name="Name")]
public string Name
{
get;
set;
}
[DataMember(Name="Model")]
public string Model
{
get;
set;
}
[DataMember(Name="Make")]
public string Make
{
get;
set;
}
Web.Config
<?xml version="1.0"?>
<configuration>
<appSettings/>
<connectionStrings/>
<system.web>
<compilation debug="true" targetFramework="4.0">
</compilation>
<authentication mode="Windows"/>
<pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID"/></system.web>
<system.serviceModel>
<services>
<service name="CarSercive.Service1" behaviorConfiguration="CarSercive.Service1Behavior">
<!-- Service Endpoints -->
<endpoint address="" binding="webHttpBinding" contract="CarSercive.IService1">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="CarSercive.Service1Behavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
this service is also publish on IIS. and I also checked that service with google chrome extension SIMPLE REST CLIENT and received an internal server error
The problem is your host name doesn't match what you are using from the phone.
You can turn off address filter to fix this temporarily:
[ServiceBehavior(AddressFilterMode=AddressFilterMode.Any)]
public class Service1 : IService1
{
....
}
But you should fix the hostname when you release to production
Create a domain in your machine with proper port number and make sure you are able to call the service using the Google's Rest client.If it works,then you won't find any issue if you call the same using your android phone.
Following article will help to setup virtual directory with proper port number.[http://www.hosting.com/support/iis7/create-new-sites-in-iis-7/]
Note you can't call localhost directly from your mobile.atleast try to call the service with ipaddress.[http://localhost/service/mycar] =>[http://DemoService/service/mycar]
The following code will help you to debug your code a little bit deep.
catch (Exception ex)
{
WebException webexception = (WebException)ex;
var responseresult = webexception.Response as HttpWebResponse;
//Code to debug Http Response
var responseStream = webexception.Response.GetResponseStream();
string fault_message = string.Empty;
int lastNum = 0;
do
{
lastNum = responseStream.ReadByte();
fault_message += (char)lastNum;
} while (lastNum != -1);
responseStream.Close();
}
Never mind, I have made several changes in web.config file and got the solution. <endpointBehaviors> tag was missing in my case and several other things. here is the updated code of web.config file.
[UPDATED web.config file]
<?xml version="1.0"?>
<configuration>
<appSettings/>
<connectionStrings>
<add name="DB" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=C:\Users\Munyb\Documents\Visual Studio 2010\Projects\CarSercive\CarSercive\App_Data\Database1.mdf;Integrated Security=True;User Instance=True" providerName="System.Data.SqlClient"/>
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.0">
</compilation>
<authentication mode="Windows"/>
<pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID"/></system.web>
<system.serviceModel>
<services>
<service name="CarSercive.Service1" behaviorConfiguration="RESTfulServ">
<!-- Service Endpoints -->
<endpoint address="" binding="webHttpBinding" contract="CarSercive.IService1" behaviorConfiguration="web"></endpoint>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="RESTfulServ">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true">
</serviceHostingEnvironment>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
</modules>
</system.webServer>
</configuration>

Categories

Resources