I am trying to get a file upload/download via a WCF service working. The transfer protocol is HTTP. I have set the binding up to user Streaming as transfer mode and have tried for days now to get it working properly, without success. I have managed to get it working for small files. When uploading large files, the file is created on the server, a number of bytes are written and then the transaction fails.
The service is hosted in a Windows Azure WebRole environment scaled to a degree which must definitely be sufficient for the task.
When inspecting the trace log with (e2e-file) with SvcTraceViewer.exe, the problem seems to be this:
An exception has been thrown when reading the stream.
with the call stack:
System.ServiceModel.Dispatcher.StreamFormatter.MessageBodyStream.Read(Byte[] buffer, Int32 offset, Int32 count)
DataService.TransferService.UploadFile(RemoteFileInfo request)
SyncInvokeUploadImage(Object , Object[] , Object[] )
System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc)
System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
The service contract looks like this:
[ServiceContract]
public interface ITransferService
{
[OperationContract]
RemoteFileInfo DownloadImage(DownloadRequest request);
[OperationContract(IsOneWay = true)]
void UploadImage(RemoteFileInfo request);
}
[MessageContract]
public class DownloadRequest
{
[MessageBodyMember]
public string FileName;
}
[MessageContract]
public class RemoteFileInfo : IDisposable
{
[MessageHeader(MustUnderstand = true)]
public string FileName;
[MessageHeader(MustUnderstand = true)]
public long Length;
[MessageBodyMember(Order = 1)]
public System.IO.Stream FileByteStream;
public void Dispose()
{
if (FileByteStream != null)
{
FileByteStream.Close();
FileByteStream = null;
}
}
}
Here is the service implementation:
public class TransferService : ITransferService
{
public RemoteFileInfo DownloadImage(DownloadRequest request)
{
return DownloadFile(request);
}
public void UploadImage(RemoteFileInfo request)
{
UploadFile(request);
}
public RemoteFileInfo DownloadFile(DownloadRequest request)
{
var result = new RemoteFileInfo();
try
{
var filePath = Path.Combine(RoleEnvironment.GetLocalResource("TempStorage").RootPath, request.FileName);
var fileInfo = new FileInfo(filePath);
if (!fileInfo.Exists)
throw new FileNotFoundException("File not found", request.FileName);
var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
result.FileName = request.FileName;
result.Length = fileInfo.Length;
result.FileByteStream = stream;
}
catch (Exception ex)
{
}
return result;
}
public void UploadFile(RemoteFileInfo request)
{
FileStream targetStream;
var sourceStream = request.FileByteStream;
var filePath = Path.Combine(RoleEnvironment.GetLocalResource("TempStorage").RootPath, request.FileName);
using (targetStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
{
const int bufferLen = 65000;
var buffer = new byte[bufferLen];
var count = 0;
while ((count = sourceStream.Read(buffer, 0, bufferLen)) > 0)
{
targetStream.Write(buffer, 0, count);
}
targetStream.Close();
sourceStream.Close();
}
}
}
I've set the web.config of the WCF service up like this to enable streaming, increase the relevant size limitations (or at least the ones I know of) and the timeouts:
<?xml version="1.0"?>
<configuration>
<system.diagnostics>
<trace autoflush="true">
<listeners>
<add type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=2.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
name="AzureDiagnostics">
<filter type="" />
</add>
</listeners>
</trace>
<sources>
<source name="System.ServiceModel"
switchValue="Information, ActivityTracing"
propagateActivity="true">
<listeners>
<add name="sdt"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData= "log.e2e" />
</listeners>
</source>
</sources>
</system.diagnostics>
<system.web>
<customErrors mode="Off" />
<compilation debug="true" targetFramework="4.0" />
<httpRuntime maxRequestLength="2097151" useFullyQualifiedRedirectUrl="true" executionTimeout="14400" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
<bindings>
<basicHttpBinding>
<binding closeTimeout="00:01:00"
openTimeout="00:01:00"
receiveTimeout="00:10:00"
sendTimeout="00:10:00"
maxReceivedMessageSize="2147483647"
maxBufferSize="2147483647"
transferMode="Streamed" >
<readerQuotas maxDepth="2147483647"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647"/>
</binding>
</basicHttpBinding>
</bindings>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
The client side is a WPF application. The calling code is this:
private void UploadImage(byte[] data, Guid guid)
{
using (var transferService = new TransferServiceClient())
using (var stream = new MemoryStream(data))
{
var uploadRequestInfo = new RemoteFileInfo();
uploadRequestInfo.FileName = guid.ToString();
uploadRequestInfo.Length = data.Length;
uploadRequestInfo.FileByteStream = stream;
transferService.UploadImage(uploadRequestInfo);
}
}
private byte[] DownloadImage(Guid guid)
{
using (var transferService = new TransferServiceClient())
{
try
{
var request = new DownloadRequest(guid.ToString());
var iconFile = transferService.DownloadImage(request);
var data = ByteArrayOperations.FromStream(iconFile.FileByteStream);
return data;
}
catch (Exception)
{
return null;
}
}
}
and - finally - the client side app.config:
<?xml version="1.0"?>
<configuration>
<configSections>
<system.web>
<httpRuntime maxRequestLength="2097150"/>
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_ITransferService"
closeTimeout="04:01:00"
openTimeout="04:01:00"
receiveTimeout="04:10:00"
sendTimeout="04:01:00"
allowCookies="false"
bypassProxyOnLocal="false"
hostNameComparisonMode="StrongWildcard"
maxBufferSize="2147483647"
maxBufferPoolSize="2147483647"
maxReceivedMessageSize="2147483647"
messageEncoding="Text"
textEncoding="utf-8"
transferMode="Streamed"
useDefaultWebProxy="true">
<readerQuotas maxDepth="128"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647" />
<security mode="None">
<transport clientCredentialType="None"
proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="xxx/TransferService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ITransferService"
contract="Transfer.ITransferService" name="BasicHttpBinding_ITransferService" />
</client>
</system.serviceModel>
</configuration>
Note that out of desparation I've added this section:
<system.web>
<httpRuntime maxRequestLength="2097150"/>
</system.web>
without any effect.
In the error log there is one more exception being thrown directly after starting up the service. I neither know what it means nor whether it is related to the problem at all:
System.ServiceModel.ProtocolException
Content Type multipart/related;
type="application/xop+xml";start="<http://tempuri.org/0>";boundary="uuid:b230e809-500b-4217-a08e-32ff49e13bac+id=5";start-info="text/xml"
was sent to a service expecting text/xml; charset=utf-8. The client
and service bindings may be mismatched.
I've spent days getting this to work and really don't know what else I can try. I would be really really happy if somebody could have a look at the configs and maybe give a hint what else to try. So, the question is:
What could be the cause for the transfer to fail and what can I do to solve this?
I would also be happy for further advice on
What to do to find the root problem here, if it cannot be identified based on the information given in the question?
Appendix: I don't think the client side exception is of any use but I would like to include it in the question to make it easier for others with the same problem to find the answers to come (hopefully):
A first chance exception of type 'System.Net.Sockets.SocketException'
occurred in System.dll
Additional information: An existing connection was forcibly closed by
the remote host
I do not see where the service binding is being specified in the serivce config file. I suspect that the configuration values are not being read and this to be the cause of why.
So I propose specifying the name of the binding in the service config file as BasicHttpBinding_ITransferService (same name used in the client config) and then adding the following under the system.serviceModel node of the configuration file:
<services>
<service name="TransferService" >
<endpoint
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_ITransferService"
contract="Transfer.ITransferService" />
</service>
</services>
Related
I am trying to consume a SOAP service and am having authentication problems and think I may be missing something useful. I think the issue may be in that I'm passing in the header more than just the credentials (which I believe is what I have to do, but think it just makes the situation more unique). Below is my config file and the code I'm using to authenticate.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="MemberSoap">
<security mode="Transport" />
</binding>
<binding name="MemberSoap1" />
<binding name="TransactionSoap">
<security mode="Transport" />
</binding>
<binding name="TransactionSoap1" />
<binding name="CertificateSoap" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" maxBufferPoolSize="2147483647">
<readerQuotas maxDepth="32" maxArrayLength="2147483647" maxStringContentLength="2147483647"/>
<security mode="Transport" />
</binding>
<binding name="CertificateSoap1" />
<binding name="MembershipSoap">
<security mode="Transport">
<transport clientCredentialType="Basic" proxyCredentialType="None" realm="" />
<message clientCredentialType="Certificate" algorithmSuite="Default" />
</security>
</binding>
<binding name="ContentSoap">
<security mode="Transport" />
</binding>
<binding name="ContentSoap1" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://membership/member.asmx"
binding="basicHttpBinding" bindingConfiguration="MemberSoap"
contract="Member.MembershipWsMemberSoap" name="Ovs.Membership.Ws.MemberSoap" />
<endpoint address="https://membership/transaction.asmx"
binding="basicHttpBinding" bindingConfiguration="TransactionSoap"
contract="MembershipWsTransactionSoap" name="TransactionSoap" />
<endpoint address="https://membership/certificate.asmx"
binding="basicHttpBinding" bindingConfiguration="CertificateSoap"
contract="MembershipWsCertificateSoap" name="CertificateSoap" />
<endpoint address="https://ngmembership/Membership.svc"
binding="basicHttpBinding" bindingConfiguration="MembershipSoap"
contract="Membership.IMembership" name="MembershipSoap" />
<endpoint address="https://membership/content.asmx"
binding="basicHttpBinding" bindingConfiguration="ContentSoap"
contract="Content.MembershipWsContentSoap" name="ContentSoap" />
</client>
</system.serviceModel>
<appSettings>
<add key="UsernameAuth" value="user" />
<add key="PasswordAuth" value="pass" />
</appSettings>
</configuration>
I left out the base url for security purposes as well as the full namespaces, but the one I'm mainly concerned about is the name="MembershipSoap" service. Here is my first attempt at the code I'm using to authenticate.
public Transaction[] GetAllBookingInfo(string memberId, string partnerId)
{
AllBookingsByMemberIdRS response;
using (var client = new MembershipClient())
using (new OperationContextScope(client.InnerChannel))
{
// add the basic auth header
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name]
= GetBasicAuthHeader("user", "pass");
var request = new AllBookingsByMemberIdRQ
{
MemberId = memberId,
PartnerId = partnerId
};
response = AuthenticateServiceUser.membershipSession.GetAllBookingsByMemberId(request);
}
var trans = response.Transactions;
return trans;
}
protected HttpRequestMessageProperty GetBasicAuthHeader(string userName, string password)
{
// get the basic auth header
HttpRequestMessageProperty httpRequestProperty = new HttpRequestMessageProperty();
httpRequestProperty.Headers[HttpRequestHeader.Authorization] = "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes(userName + ":" + password));
return httpRequestProperty;
}
At this I get an error saying that there were 'Invalid web service credentials used'. So after reading I switched the first method to this.
public Transaction[] GetAllBookingInfo(string memberId, string partnerId)
{
AllBookingsByMemberIdRS response;
var client = new MembershipClient();
client.ClientCredentials.UserName.UserName = "user";
client.ClientCredentials.UserName.Password = "pass";
using (new OperationContextScope(client.InnerChannel))
{
var request = new AllBookingsByMemberIdRQ
{
MemberId = memberId,
PartnerId = partnerId
};
response = AuthenticateServiceUser.membershipSession.GetAllBookingsByMemberId(request);
}
var trans = response.Transactions;
return trans;
}
And now I'm getting a 'The username is not provided. Specify username in ClientCredentials' error. So now I feel like I'm moving further away to where I was before. Maybe someone can shed some light on this? Thanks in advance!
I figured it out. I stupidly reference another client in my code - one without credentials. It's always those simple mistakes that get overlooked.
public Transaction[] GetAllBookingInfo(string memberId, string partnerId)
{
AllBookingsByMemberIdRS response;
using (var client = new MembershipClient())
using (new OperationContextScope(client.InnerChannel))
{
// add the basic auth header
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name]
= GetBasicAuthHeader("user", "pass");
var request = new AllBookingsByMemberIdRQ
{
MemberId = memberId,
PartnerId = partnerId
};
response = client.GetAllBookingsByMemberId(request);
}
return response.Transactions;
}
I have very little experience in WCF and I want to upload file on server from client machine via WCF service (using streaming). I read few topics and wrote a simple example by myself, but unfortunately it's not working
This is an interface code:
[ServiceContract]
public interface IService1
{
[OperationContract]
string UpStream(FileStream inStream);
}
This is implementation:
public string UpStream(FileStream inStream)
{
using(StreamReader sr = new StreamReader(inStream))
{
var recievedText = sr.ReadToEnd();
if (recievedText != "")
{
return recievedText;
}
else
{
return "nothing";
}
}
}
This is a client code:
private void button3_Click(object sender, EventArgs e)
{
service2.Service1Client sc = new service2.Service1Client();
OpenFileDialog opf = new OpenFileDialog();
opf.ShowDialog();
if (opf.FileName != "")
{
using (FileStream inStream = File.Open(opf.FileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
MessageBox.Show(sc.UpStream(inStream));
}
}
}
I think that problem must be somewhere in config file or in Stream. When I start client program and invoke UpStream method, WCF-service is recieving an empty stream
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services />
<bindings>
<basicHttpBinding>
<binding name="NewBinding0" maxBufferPoolSize="52428800" maxBufferSize="65536000"
maxReceivedMessageSize="6553600000" transferMode="Streamed"
useDefaultWebProxy="true" />
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
If anyone can help me with solving my problem, I'll be very grateful
Streaming is very useful but a little tricky to get your head around
this MSDN article provides lots of details https://msdn.microsoft.com/en-us/library/ms733742%28v=vs.110%29.aspx
but doesn't make some of the details very clear
firstly you need to pass messages rather than parameters
this would look something like
[MessageContract]
public class DataTransfer
{
[MessageHeader(MustUnderstand = true)]
public DataContract.HandShake Handshake { get; set; }
[MessageBodyMember(Order = 1)]
public Stream Data { get; set; }
//notice that it is using the default stream not a file stream, this is because the filestream you pass in has to be changed to a network stream to be sent via WCF
}
where the HandShake class provides the parameters you need to include along with your stream
public SaveResponse SaveData(DataTransfer request)
{
using (var stream = new System.IO.MemoryStream())
{
request.Data.CopyTo(stream);
stream.Position = 0;
//this is because you have less control of a stream over a network than one held locally, so by copying from the network to a local stream you then have more control
next is configuration: you have to configure for streaming on both the server and client
which requires something like this
<bindings>
<basicHttpBinding>
<binding name="ServiceBinding" transferMode="Streamed" messageEncoding="Mtom" maxReceivedMessageSize="67108864" maxBufferSize="65536" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00">
</binding>
</basicHttpBinding>
</bindings>
I need to upload a big file to Azure storage. As a first step, I am trying to upload the file to web service folder via wcf service. I followed the steps in this link Streaming files over WCF. My service code:
namespace MilkboxGames.Services
{
[ServiceContract]
public interface IFileUploadService
{
[OperationContract]
UploadResponse Upload(UploadRequest request);
}
[MessageContract]
public class UploadRequest
{
[MessageHeader(MustUnderstand = true)]
public string BlobUrl { get; set; }
[MessageBodyMember(Order = 1)]
public Stream data { get; set; }
}
[MessageContract]
public class UploadResponse
{
[MessageBodyMember(Order = 1)]
public bool UploadSucceeded { get; set; }
}
}
And
namespace MilkboxGames.Services
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Single)]
public class FileUploadService : IFileUploadService
{
#region IFileUploadService Members
public UploadResponse Upload(UploadRequest request)
{
try
{
string uploadDirectory = System.AppDomain.CurrentDomain.BaseDirectory;
string path = Path.Combine(uploadDirectory, "zacharyxu1234567890.txt");
if (File.Exists(path))
{
File.Delete(path);
}
const int bufferSize = 2048;
byte[] buffer = new byte[bufferSize];
using (FileStream outputStream = new FileStream(path, FileMode.Create, FileAccess.Write))
{
int bytesRead = request.data.Read(buffer, 0, bufferSize);
while (bytesRead > 0)
{
outputStream.Write(buffer, 0, bytesRead);
bytesRead = request.data.Read(buffer, 0, bufferSize);
}
outputStream.Close();
}
return new UploadResponse
{
UploadSucceeded = true
};
}
catch (Exception ex)
{
return new UploadResponse
{
UploadSucceeded = false
};
}
}
#endregion
}
}
Web.config:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="false" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" executionTimeout="600"
maxRequestLength="2097152" />
<customErrors mode="Off"/>
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="FileUploadServiceBinding" messageEncoding="Mtom" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" maxBufferPoolSize="2147483647" receiveTimeout="00:15:00" sendTimeout="00:10:00" openTimeout="00:10:00" closeTimeout="00:10:00" transferMode="Streamed">
<security mode="None">
<transport clientCredentialType="None" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="MilkboxGames.Services.FileUploadService" behaviorConfiguration="FileUploadServiceBehavior">
<endpoint address=""
binding="basicHttpBinding" contract="MilkboxGames.Services.IFileUploadService" bindingConfiguration="FileUploadServiceBinding">
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="FileUploadServiceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="2147483648" />
</requestFiltering>
</security>
</system.webServer>
</configuration>
To consume this service, I created a console application and added the wcf service to Service References. I noticed that the service method becomes 'public bool Upload(string BlobUrl, System.IO.Stream data)' instead of 'public UploadResponse Upload(UploadRequest request)'. Can somebody explain to me why?
Client code:
string blobUrl = "assassinscreedrevelationsandroid/GT-I9100G/assassinscreedrevelationsandroid.apk";
string fileName = "C:\\ws_new\\XuConsoleApplication\\XuConsoleApplication\\bin\\Debug\\motutcimac.myar";
bool bUploadBlobResult;
byte[] buffer = File.ReadAllBytes(fileName);
Console.WriteLine("Size = " + buffer.Length);
Stream fileStream = System.IO.File.OpenRead(fileName);
FileUploadServiceClient objFileUploadServiceClient = new FileUploadServiceClient();
bUploadBlobResult = objFileUploadServiceClient.Upload(blobUrl, fileStream);
I managed to upload a file of 123.8MB. When I try to upload a file of 354.6MB, I got the following exception:
Unhandled Exception: System.InsufficientMemoryException: Failed to allocate
a managed memory buffer of 371848965 bytes. The amount of available memory
may be low. ---> System.OutOfMemoryException: Exception of type
'System.OutOfMemoryException' was thrown.
at System.Runtime.Fx.AllocateByteArray(Int32 size)
--- End of inner exception stack trace ---
I am unable to figure out why this happened. Any help or advice are appreciated.
Unhandled Exception: System.InsufficientMemoryException: Failed to
allocate a managed memory buffer of 371848965 bytes. The amount of
available memory may be low.
above message is indicating your app is using up all the memory that allowed, to increase the limit i think you will need a larger value on attribute "maxReceivedMessageSize"
also from another thread (Failed to allocate a managed memory buffer of 134217728 bytes. The amount of available memory may be low), it recommend to use stream transfer mode for large file upload.
Use Stream property in message contract of WCF operation to transfer
large objects.
[MessageContract]
public class DocumentDescription
{
[MessageBodyMember(Namespace = "http://example.com/App")]
public Stream Stream { get; set; }
}
Configure your binding this way
<binding name="Binding_DocumentService" receiveTimeout="03:00:00"
sendTimeout="02:00:00" transferMode="Streamed" maxReceivedMessageSize="2000000">
<security mode="Transport" />
</binding>
I am trying to create a WCF client APP that is consuming a JAVA WS that uses three certificates of which two of them aer for signing and encryption and one is for transport. There is a private key that is installed on the server and a public certificate file was exported from the JKS keystore file. I have installed the public key and keys for signing and encryption into certificate store via MMC under Personal certificates.
Here is My Code from Form:
public Form1()
{
InitializeComponent();
ServicePointManager.SecurityProtocol=SecurityProtocolType.Tls;
referencaServisa.obrtniWsServiceClient klijent = new referencaServisa.SomeServiceClient();
var vs = klijent.Endpoint.Behaviors.Where((i) => i.GetType().Namespace.Contains("VisualStudio"));
klijent.Endpoint.Behaviors.Remove((System.ServiceModel.Description.IEndpointBehavior)vs.Single());
klijent.Endpoint.Address = new System.ServiceModel.EndpointAddress(#"https://213.147.119.174:4444/some-registar-ws/someWsService");
CustomBinding binding = new CustomBinding();
SecurityBindingElement sbe = SecurityBindingElement.CreateMutualCertificateDuplexBindingElement(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10);
AsymmetricSecurityBindingElement asymetricElement=(AsymmetricSecurityBindingElement)sbe;
asymetricElement.DefaultAlgorithmSuite = System.ServiceModel.Security.SecurityAlgorithmSuite.Basic128Rsa15;
asymetricElement.ProtectTokens = true;
asymetricElement.IncludeTimestamp = false;
asymetricElement.SetKeyDerivation(false);
asymetricElement.EnableUnsecuredResponse = true;
asymetricElement.SecurityHeaderLayout = SecurityHeaderLayout.Lax;
asymetricElement.KeyEntropyMode = SecurityKeyEntropyMode.ClientEntropy;
asymetricElement.AllowSerializedSigningTokenOnReply=true;
X509SecurityTokenParameters initiator = new X509SecurityTokenParameters(X509KeyIdentifierClauseType.SubjectKeyIdentifier, SecurityTokenInclusionMode.AlwaysToInitiator);
/*X509SecurityTokenParameters recipient = new X509SecurityTokenParameters(X509KeyIdentifierClauseType.RawDataKeyIdentifier, SecurityTokenInclusionMode.AlwaysToInitiator);
asymetricElement.RecipientTokenParameters = recipient;
asymetricElement.InitiatorTokenParameters = initiator;
asymetricElement.InitiatorTokenParameters.RequireDerivedKeys = false;*/
asymetricElement.MessageProtectionOrder = System.ServiceModel.Security.MessageProtectionOrder.SignBeforeEncrypt;
asymetricElement.LocalClientSettings.IdentityVerifier = new MyIdentityVerifier();
asymetricElement.EndpointSupportingTokenParameters.Signed.Add(
new X509SecurityTokenParameters());
binding.Elements.Clear();
binding.Elements.Add(asymetricElement);
CustomTextMessageBindingElement customTextMessageBindingElement = new CustomTextMessageBindingElement("UTF-8", "text/xml", MessageVersion.Soap11);
binding.Elements.Add(customTextMessageBindingElement);
HttpsTransportBindingElement httpsTransportBindingElement = new HttpsTransportBindingElement
{
RequireClientCertificate=true
};
httpsTransportBindingElement.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
httpsTransportBindingElement.TransferMode = TransferMode.Buffered;
httpsTransportBindingElement.UseDefaultWebProxy = true;
httpsTransportBindingElement.KeepAliveEnabled=true;
httpsTransportBindingElement.AuthenticationScheme = AuthenticationSchemes.Digest;
httpsTransportBindingElement.RequireClientCertificate = true;
binding.Elements.Add(httpsTransportBindingElement);
klijent.Endpoint.Binding = binding;
referencaServisa.statusType status;
string poruka;
referencaServisa.registarskiUlozak[] registarskiUlosci;
System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
// Begin using the client.
try
{
klijent.Open();
status = klijent.getUlosciByMbo("90445066",false, out poruka, out registarskiUlosci);
referencaServisa.ulozak receivedUlozak = null;
if (status.ToString() == "OK")
{
receivedUlozak = registarskiUlosci[0].aktivnoStanjeUloska.ulozak;
MessageBox.Show(receivedUlozak.vlasnici[0].redniBroj.ToString());
}
MessageBox.Show(status.ToString());
// Close the client.
klijent.Close();
}
catch (ProtocolException ex) { MessageBox.Show(ex.Message); }
}
So I use three certificates one for signing one for encryption and one for SSL transport. I use custom binding for separation of certificates. When I start my app I get an error General security error:
The content type text/xml;charset=UTF-8 of the response message does not match the content type of the binding (text/xml; charset=UTF-8). If using a custom encoder, be sure that the IsContentTypeSupported method is implemented properly. The first 394 bytes of the response were: '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><soap:Fault><faultcode xmlns:ns1="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">ns1:InvalidSecurity</faultcode><faultstring>An error was discovered processing the <wsse:Security> header (Unsupported key identification)</faultstring></soap:Fault></soap:Body></soap:Envelope>'.
Here is my app.config :
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="dasda12312.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1" />
</startup>
<system.net>
<settings>
<httpWebRequest useUnsafeHeaderParsing="false"/>
</settings>
</system.net>
<system.diagnostics>
<switches>
<add name="Remote.Disable" value="1"/>
</switches>
</system.diagnostics>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="MyClientCredentialsExtension">
<MyClientCredentialsExtension>
<clientCertificate findValue="removed" storeLocation="LocalMachine" x509FindType="FindBySerialNumber" storeName="My" />
<serviceCertificate>
<defaultCertificate findValue="removed" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
</serviceCertificate>
<transportCertificate findValue="removed" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySerialNumber"/>
</MyClientCredentialsExtension>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<customBinding>
<binding name="cb">
<security authenticationMode="MutualCertificate" requireDerivedKeys="true" includeTimestamp="true"
allowSerializedSigningTokenOnReply="true" securityHeaderLayout="Lax"
defaultAlgorithmSuite="Basic256"
keyEntropyMode="ClientEntropy" requireSecurityContextCancellation="false"
messageProtectionOrder="SignBeforeEncrypt" messageSecurityVersion="WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10" />
<textMessageEncoding messageVersion="Soap11" />
<httpsTransport />
</binding>
</customBinding>
<client>
<!---->
<endpoint address=""
behaviorConfiguration="MyClientCredentialsExtension" binding="customBinding" bindingConfiguration="cb"
contract="referencaServisa.someWsService"
name="SomeWsServiceImplPort">
</endpoint>
</client>
<extensions>
<behaviorExtensions>
<add name="MyClientCredentialsExtension" type="SEOP.MyClientCredentialsExtensionElement,dasda12312"/>
</behaviorExtensions>
</extensions>
</system.serviceModel>
<applicationSettings>
<dasda12312.Properties.Settings>
<setting name="dasda12312_someReferenca2_someWsService" serializeAs="string">
<value>https://213.147.119.174:4444/some-registar-ws/someWsService</value>
</setting>
</dasda12312.Properties.Settings>
</applicationSettings>
</configuration>
Anyone had similar problem please help me and tell me how to fix this.
Thank you.
We have a RIA Services call that only passes a couple of parameters, however it can take an extended period of time to process (e.g. 20+ minutes) When it hits around the 10 to 15 minute mark, we get an Error 404 Not Found exception. Here are the things we've done so far to take care of any timeout issues:
WebConfig - ServerSide
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
<bindings>
<basicHttpBinding>
<binding name="" closeTimeout="01:00:00" openTimeout="01:00:00"
receiveTimeout="01:00:00" sendTimeout="01:00:00" maxBufferSize="2147483647"
maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="Transport"/>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
</behavior>
</serviceBehaviors>
</behaviors>
Changed the WcfTimeouts:
public static class DomainContextExtensions
{
public static void ChangeWcfTimeouts(this DomainContext context)
{
PropertyInfo channelFactoryProperty =
context.DomainClient.GetType().GetProperty("ChannelFactory");
if (channelFactoryProperty == null)
{
throw new InvalidOperationException(
"There is no 'ChannelFactory' property on the DomainClient.");
}
TimeSpan timeout = new TimeSpan(1, 0, 0); // 1 Hour
ChannelFactory factory = (ChannelFactory)channelFactoryProperty.GetValue(context.DomainClient, null);
factory.Endpoint.Binding.SendTimeout = timeout;
factory.Endpoint.Binding.CloseTimeout = timeout;
factory.Endpoint.Binding.OpenTimeout = timeout;
factory.Endpoint.Binding.ReceiveTimeout = timeout;
}
}
Neither seems to affect the issue. Any and all ideas are welcome!