mismatch between server and client - wcf

I have a WCF rest service. I created it using 4.0 rest service application, so it is SVC-less.
I have this service contract:
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class Service1
{
[WebGet(UriTemplate = "/Login/?username={username}&password={password}", ResponseFormat= WebMessageFormat.Json)]
public Response Login(string username, string password)
{
Response res;
BillboardsDataContext db = new BillboardsDataContext();
var q = from lgin in db.logins
where lgin.username == username && lgin.password == password
select lgin;
if (q.Count() != 0)
{
res = new Response(true, "Login successful");
return res;
}
else
{
res = new Response(false, "Login failed!");
return res;
}
}
[WebInvoke(UriTemplate = "", Method = "POST")]
public void Upload(Stream fileStream)
{
FileStream targetStream = null;
string uploadFolder = #"C:\inetpub\wwwroot\Upload\test.jpg";
using (targetStream = new FileStream(uploadFolder, FileMode.Create,
FileAccess.Write, FileShare.None))
{
const int bufferLen = 65000;
byte[] buffer = new byte[bufferLen];
int count = 0;
while ((count = fileStream.Read(buffer, 0, bufferLen)) > 0)
{
targetStream.Write(buffer, 0, count);
}
targetStream.Close();
fileStream.Close();
}
}
}
and this web.config:
<services>
<service name="BillboardServices.Service1" behaviorConfiguration="Meta">
<endpoint name="restful" address="" binding="webHttpBinding" behaviorConfiguration="REST" contract="BillboardServices.Service1" />
<endpoint name="streamFile" address="/Upload" binding="basicHttpBinding" bindingConfiguration="streamBinding" contract="BillboardServices.Service1" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="REST">
<webHttp/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="Meta">
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="streamBinding" maxReceivedMessageSize="64000" maxBufferSize="64000" transferMode="Streamed" messageEncoding="Mtom">
<readerQuotas maxDepth="64000" maxStringContentLength="64000" maxArrayLength="64000" maxBytesPerRead="64000" maxNameTableCharCount="64000"/>
</binding>
</basicHttpBinding>
</bindings>
The login service works very well, but I am having an issue with the Upload action. I call it through an Android app via http://www.myhost.com/Upload and I get this error:
Content Type multipart/form-data; boundary=wjtUI0EFrpQhBPtGne9le5_-yMxPZ_sxZJUrFf- was sent to a service expecting multipart/related; type="application/xop+xml". The client and service bindings may be mismatched.
I can't find info on this error. Anybody seen this before?
Thank you!

So it turns out that I needed to use webHttpBinding for both endpoints, not just the login.

Related

SwaggerWCF configuration for self hosted WCF library

I'm having some difficulties getting SwaggerWCF to load my documentation page, and I'm not sure why. I get no errors, but I also get no Swagger docs either, just a 404 when I visit http://localhost:8733/docs per the endpoint configuration. What am I doing wrong here? I have everything decorated up, using Framework 4.8. Service works fine and the mex and js endpoints will return data, just no swaggerUI.
Here is my App.Config:
<system.serviceModel>
<standardEndpoints>
<webHttpEndpoint>
<standardEndpoint name="" contentTypeMapper="Microsoft.Samples.WebContentTypeMapper.JsonContentTypeMapper, JsonContentTypeMapper, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</webHttpEndpoint>
</standardEndpoints>
<services>
<service name="AutodeskVaultAPI.VaultWorker">
<endpoint address="" binding="basicHttpBinding" contract="AutodeskVaultAPI.IVaultServices">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<endpoint address="js" behaviorConfiguration="jsonEP" binding="webHttpBinding"
name="jsonEP" contract="AutodeskVaultAPI.IVaultServices" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8733/AutodeskVaultAPI/" />
</baseAddresses>
</host>
</service>
<service name="SwaggerWcf.SwaggerWcfEndpoint">
<endpoint address="http://localhost:8733/docs" binding="webHttpBinding" contract="SwaggerWcf.ISwaggerWcfEndpoint" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True" />
<serviceDebug includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="jsonEP">
<webHttp helpEnabled="true" automaticFormatSelectionEnabled="true"/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
Here is my service implementation:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[SwaggerWcf("/AutodeskVaultAPI/js")]
public class VaultWorker : IVaultServices
{
...[redacted]...
[SwaggerWcfTag("AutodeskVaultAPI")]
public AutodeskVaultFolder GetRootFolder(string vaultServerName = "", string currentUserLogin = "false")
{
try
{
Folder rootFolder = VaultConnection.WebServiceManager.DocumentService.GetFolderRoot();
if (null == rootFolder)
return null;
else
{
var toReturn = new AutodeskVaultFolder()
{
Created = rootFolder.CreateDate,
Category = (null == rootFolder.Cat) ? "No Category" : rootFolder.Cat.CatName,
CreatedByUserID = rootFolder.CreateUserId,
CreatedByUserName = rootFolder.CreateUserName,
EntityMasterID = rootFolder.Id,
FolderEntityName = rootFolder.Name,
FolderFullPath = rootFolder.FullName,
IsVaultRoot = true,
NumberOfChildren = rootFolder.NumClds,
ParentID = rootFolder.ParId
};
return toReturn;
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
return null;
}
}
[SwaggerWcfTag("AutodeskVaultAPI")]
public AutodeskVaultSearchResponse SearchVault(AutodeskVaultSearchRequest request)
{
try
{
string bookMark = string.Empty;
var parameters = getSearchParametersFromRequest(request);
SrchStatus srchStatus = null;
List<File> foundFiles = new List<File>();
if (null != parameters && parameters.Length > 0)
{
while (null == srchStatus || foundFiles.Count < srchStatus.TotalHits)
{
File[] srcResults = VaultConnection.WebServiceManager.DocumentService.FindFilesBySearchConditions(parameters, null, null, true, false, ref bookMark, out srchStatus);
if (null != srcResults)
foundFiles.AddRange(srcResults);
else
break;
}
}
return mapResultsToResponse(request, foundFiles);
}
catch (Exception ex)
{
Debug.Write(ex);
return null;
}
}
...[redacted]...
[DataContract(Name = "AutodeskVaultSearchRequest")]
public class AutodeskVaultSearchRequest
{
[DataMember]
public bool OR_Search = false;
[DataMember]
public List<AutodeskVaultProperty> properties;
}
[DataContract(Name = "AutodeskVaultSearchResponse")]
public class AutodeskVaultSearchResponse
{
[DataMember]
public AutodeskVaultSearchRequest Request;
[DataMember]
public List<AutodeskVaultFile> Files;
[DataMember]
public string Message;
and here is my service interface:
[ServiceContract]
public interface IVaultServices
{
[SwaggerWcfPath("GetRootFolder", #"Test the default configured server to see if we can get back the root folder")]
[OperationContract]
[WebInvoke(UriTemplate = "GetRootfolder/{vaultServerName}/{currentUserLogin}", Method = "GET", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
[Description(#"Test the default configured server to see if we can get back the root folder")]
AutodeskVaultFolder GetRootFolder(string vaultServerName = "", string currentUserLogin = "false");
[SwaggerWcfPath("GetAsbuiltDrawingsByNumber", #"Given an Autodesk Search Request, search through Vault to find File information using the supplied properties.")]
[OperationContract]
[WebInvoke(UriTemplate = "SearchVault", Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
[Description(#"Given an Autodesk Search Request, search through Vault to find File information using the supplied properties.")]
AutodeskVaultSearchResponse SearchVault(AutodeskVaultSearchRequest request);
}
Add an endpoint to your App.config file.
<services>
<service name="SwaggerWcf.SwaggerWcfEndpoint">
<endpoint address="http://localhost/docs" binding="webHttpBinding" contract="SwaggerWcf.ISwaggerWcfEndpoint" />
</service>
</services>
Create a WebServiceHost
var swaggerHost = new WebServiceHost(typeof(SwaggerWcfEndpoint));
swaggerHost.Open();
You can refer to the steps provided in the link for details.
https://github.com/abelsilva/swaggerwcf
How do I view my Swagger docs when using SwaggerWcf?

WCF Service receives null request

var dataToSend = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(mi));
var req = HttpWebRequest.Create("http://localhost/Service1.svc/json/MethodName");
req.ContentType = "application/json";
req.ContentLength = dataToSend.Length;
req.Method = "POST";
req.GetRequestStream().Write(dataToSend, 0, dataToSend.Length);
var response = req.GetResponse();
Here "/json" is my endpoint address and my service is configured with multiple endpoints. As per image here, request i sent is recieving null at server.
If my request format is not proper then suggest proper way to call this service.
// Service inter face
[ServiceContract]
public interface IService
{
[OperationContract]
[WebInvoke(Method="POST")]
Response MethodName(Request request);
}
// Service1
public class Service1 : IService
{
public Response MethodName(Request request)
{
some logical operation....
}
}
// End point configuration (Web config)
<endpoint address="json" behaviorConfiguration="jsonBehavior"
binding="webHttpBinding" bindingConfiguration="webHttpBindingJson"
name="jsonn" contract="Service1.IService" />
<endpoint address="xml" behaviorConfiguration="poxBehavior" binding="webHttpBinding"
bindingConfiguration="webHttpBindingXml" name="xmll" contract="Service1.IService" />
<endpointBehaviors>
<behavior name="jsonBehavior">
<enableWebScript />
</behavior>
<behavior name="poxBehavior">
<enableWebScript />
</behavior>
</endpointBehaviors>
<webHttpBinding>
<binding name="webHttpBindingJson">
<security mode="None" />
</binding>
<binding name="webHttpBindingXml">
<security mode="None" />
</binding>
</webHttpBinding>
// Request class
[DataContract]
public class Request
{
string userMobile;
string otp;
[DataMember]
public string UserMobile
{
get { return userMobile; }
set { userMobile = value; }
}
[DataMember]
public string OTP
{
get { return otp; }
set { otp = value; }
}
}
Finally i found for this.
I modified endpoint of json behaviour configuration to this,
<behavior name="jsonBehavior">
<webHttp defaultBodyStyle ="Bare"/>
<!--<enableWebScript />-->
</behavior>
and removed enableWebScript. Finally my code working.

WCF jquery parsererror unterminated string constant response

For my recent project, I created a Web service that returns an array of custom type to jquery client-side code. WCF is called by $.ajax command and is in the same domain.
When I run my web applicaiton on localhost (which is IIS run on local machine), everything works fine. When I deploy it to our integration server, suddenly ajax call to WCF ends with an error: "parsererror - unterminated string constant" and status of 200. Returned message is however something like "[{\"Text\":\"Test dodatnih naslov", which of course is not a correct json format.
Correct response should have been: "[{"Text":"Test dodatnih naslovov","Value":"100"},{"Text":"Test dodatnih naslovov - ISO2","Value":"101"},{"Text":"UPDATE","Value":"102"}]"
I have traced WCf service for malfuncitons, but it does not seem to be crashing. I also tried and set timeout to ajax call, but to no avail. Some help would be much appreciated.
My IIS is IIS7, where integration runs IIS6 on Windows Server 2008.
js file
function InsuranceClientContact_ItemsRequesting(o, e) {
var $ = $telerik.$;
var urlSvc = ServiceBaseUrl + '/GetContacts'
$.ajax({
type: "POST",
url: urlSvc,
data: '{"ixClient": ' + selectedItemId + '}', //selectedItemId is a positive number
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (data) {
// do something
},
error: function (result) {
var msg = result.status + " - " + result.statusText;
setTimeout(function () { throw new Error(msg) }, 0);
}
});
wcf interface
namespace Sid.Skode.Web.Services.Populate {
[ServiceContract]
public interface IInsuranceClientContactService {
[OperationContract]
[WebInvoke(Method="POST",
BodyStyle=WebMessageBodyStyle.WrappedRequest,
ResponseFormat=WebMessageFormat.Json)]
Contact[] GetContacts(long ixClient);
}
[DataContract]
public class Contact {
[DataMember]
public string Text;
[DataMember]
public string Value;
}
}
wcf service implementation
namespace Sid.Skode.Web.Services.Populate {
[AspNetCompatibilityRequirements( RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed )]
public class InsuranceClientContactService : IInsuranceClientContactService {
public Contact[] GetContacts( long ixClient ) {
return GetContactsFromDatabase( ixClient );
}
#region Private methods
private Contact[] GetContactsFromDatabase( long ixClient ) {
DataTable dt = GetDataFromDataBaseById( ixClient );
return ConvertDataTableToContactArray( dt );
}
private DataTable GetDataFromDataBaseById( long ixClient ) {
AutoCompleteBLL model = new AutoCompleteBLL();
return model.SearchContactsByPartner( ixClient );
}
private Contact[] ConvertDataTableToContactArray( DataTable dt ) {
Contact[] rgContact = new Contact[dt.Rows.Count];
int cnContact = 0;
foreach (DataRow dr in dt.Rows) {
if (!dr.IsNull( "NAZIV" )) {
Contact contact = new Contact();
contact.Text = dr["NAZIV"].ToString();
contact.Value = dr["ID_DODATEN_KONTAKT"].ToString();
rgContact[cnContact++] = contact;
}
}
return rgContact;
}
#endregion
}
}
web.config wcf part
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="httpServiceBehavior">
<serviceMetadata httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="httpEndpointBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="webHttpBindingWithTransportWindowsSecurity">
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</webHttpBinding>
</bindings>
<serviceHostingEnvironment multipleSiteBindingsEnabled="false" aspNetCompatibilityEnabled="true" />
<services>
<service name="Sid.Skode.Web.Services.Populate.InsuranceClientContactService" behaviorConfiguration="httpServiceBehavior">
<endpoint address="" binding="webHttpBinding" bindingConfiguration="webHttpBindingWithTransportWindowsSecurity"
contract="Sid.Skode.Web.Services.Populate.IInsuranceClientContactService"
behaviorConfiguration="httpEndpointBehavior">
</endpoint>
<endpoint
address="mex"
binding="mexHttpsBinding"
bindingConfiguration=""
contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>
As described here, you need remove all instances of RadCompression http module from web config. Then, it works.

WCF service selfhosting

I am creating a WCF service with self hosting. I have found the following error i.e.:
The target assembly contains no service types. You may need to adjust the Code Access Security policy of this assembly.
The codes are as follows:
namespace MyJobs
{
public interface IJobsSvc
{
[OperationContract]
DataSet GetJobs();
[OperationContract]
Job GetJobInfo(int JobId);
[OperationContract]
List<Job> GetAllJobs();
}
}
namespace MyJobs
{
[DataContract]
public class Job
{
[DataMember]
public int JobId { get; set;}
[DataMember]
public string Description{get;set;}
[DataMember]
public int MinLevel { get; set; }
[DataMember]
public int MaxLevel { get; set; }
}
}
namespace MyJobs
{
public class JobsSvc:IJobsSvc
{
#region IJobsSvc Members
public System.Data.DataSet GetJobs()
{
string str = #"data source=PERSONAL-659BE4;database=practice;integrated security=true";
DataSet ds = new DataSet();
SqlConnection cn = new SqlConnection(str);
SqlDataAdapter da = new SqlDataAdapter("select * from Job1",cn);
da.Fill(ds);
return ds;
}
public Job GetJobInfo(int JobId)
{
string str = #"data source=PERSONAL-659BE4;database=practice;integrated security=true";
SqlConnection cn = new SqlConnection(str);
SqlCommand cmd = new SqlCommand("select * from Job1 where JobId="+JobId,cn);
cn.Open();
SqlDataReader dr = cmd.ExecuteReader();
Job obj = new Job();
if (dr.Read())
{
obj.JobId = JobId;
obj.Description = dr[1].ToString();
obj.MinLevel = Convert.ToInt32(dr[2]);
obj.MaxLevel = Convert.ToInt32(dr[3]);
}
else
{
obj.JobId = -1;
}
return obj;
}
public List<Job> GetAllJobs()
{
throw new NotImplementedException();
}
#endregion
}
}
The app.config file is:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<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="MyJobs.Job">
<endpoint address="" binding="wsHttpBinding" contract="MyJobs.IJobsSvc">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8732/Design_Time_Addresses/Jobs/MyJobs/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information,
set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="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>
You need to add [ServiceContract] attribute to your IJobSvc interface
Update
Create the behavior to expose the metadata.
<serviceBehaviors>
<behavior name="SimpleServiceBehavior">
<!-- To avoid disclosing metadata information,
set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="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>
Then configure your service with this behavior:
<service name="MyJobs.Job" behaviorConfiguration="SimpleServiceBehavior">
<endpoint address="" binding="wsHttpBinding" contract="MyJobs.IJobsSvc">

CheckAccessCore not being called in custom ServiceAuthorizationManager

I am working on a WCF REST service that will be hosted within Azure and want to check the user id. To this end I have created a custom ServiceAuthorizationManager.
namespace SecureService
{
public class AccessControlServiceAuthorizationManager : ServiceAuthorizationManager
{
String serviceNamespace = String.Empty;
String acsHostname = String.Empty;
String trustedTokenPolicyKey = String.Empty;
String trustedAudience = String.Empty;
public AccessControlServiceAuthorizationManager()
{
try
{
serviceNamespace = RoleEnvironment.GetConfigurationSettingValue("serviceNamespace");
acsHostname = RoleEnvironment.GetConfigurationSettingValue("acsHostname");
trustedTokenPolicyKey = RoleEnvironment.GetConfigurationSettingValue("trustedTokenPolicyKey");
trustedAudience = RoleEnvironment.GetConfigurationSettingValue("trustedAudience");
}
catch
{
GenerateErrorResponse();
}
finally
{
}
} // end AccessControlServiceAuthorizationManager() Constructor
protected override bool CheckAccessCore(OperationContext operationContext)
{
String headerValue = WebOperationContext.Current.IncomingRequest.Headers[HttpRequestHeader.Authorization];
String token = String.Empty;
string[] nameValuePair = null;
TokenValidator validator = null;
if (String.IsNullOrEmpty(headerValue))
{
GenerateErrorResponse();
return false;
}
if (!headerValue.StartsWith("WRAP "))
{
GenerateErrorResponse();
return false;
}
nameValuePair = headerValue.Substring("WRAP ".Length).Split(new char[] { '=' }, 2);
if (nameValuePair.Length != 2 ||
nameValuePair[0] != "access_token" ||
!nameValuePair[1].StartsWith("\"") ||
!nameValuePair[1].EndsWith("\""))
{
GenerateErrorResponse();
return false;
}
token = nameValuePair[1].Substring(1, nameValuePair[1].Length - 2);
validator = new TokenValidator(acsHostname, serviceNamespace, trustedAudience, trustedTokenPolicyKey);
if (!validator.Validate(token))
{
GenerateErrorResponse();
return false;
}
return true;
}
public void GenerateErrorResponse()
{
}
}
}
My Web.config is as follows;
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<behaviors>
<serviceBehaviors>
<behavior name="Secure">
<serviceAuthorization serviceAuthorizationManagerType="SecureService.AccessControlServiceAuthorizationManager" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="SecureService.Demo">
<endpoint address="" behaviorConfiguration="webBehavior" binding="webHttpBinding" bindingConfiguration="" contract="SecureService.IDemo" />
<endpoint address="rest" behaviorConfiguration="webBehavior" binding="webHttpBinding" bindingConfiguration="" contract="SecureService.IDemo" />
</service>
</services>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</modules>
</system.webServer>
However the CheckAccessCore() method does not seem to be called when I call the service via IE. So the question is how can I ensure it is called and therefore ensure that my users are validated.
I have put a break point in the CheckAccessCore and it never seems to get hit.
And just to make things really interesting - I will need to call this webservice from within Silverlight.
Thanks in advance
Ignore your 'services' section in config. Try:
<standardEndpoints>
<webHttpEndpoint>
<standardEndpoint crossDomainScriptAccessEnabled="True" automaticFormatSelectionEnabled="true" helpEnabled="True"/>
</webHttpEndpoint>
</standardEndpoints>
Following the configuration pasted above, I see that service behavior "Secure" is missed to apply on Service. Please check it, if it's not a typo...