Content-Type header value missing after upgrade to WCF Data Services 5.0 - wcf

After upgrading to WCF Data Services 5.0 for OData V3 i can't make insert or updates.
The only thing that is possible are selects.
EDIT
Exception in overridden method HandleException:
Exception:
System.Data.Services.DataServiceException: Content-Type header value missing.
at System.Data.Services.HttpProcessUtility.ReadContentType(String contentType, String& mime, Encoding& encoding)
at System.Data.Services.Serializers.Deserializer.CreateDeserializer(RequestDescription description, IDataService dataService, Boolean update, UpdateTracker tracker)
at System.Data.Services.DataService1.HandlePostOperation(RequestDescription description, IDataService dataService)
at System.Data.Services.DataService1.ProcessIncomingRequest(RequestDescription description, IDataService dataService)
at System.Data.Services.DataService1.HandleNonBatchRequest(RequestDescription description)
at System.Data.Services.DataService1.HandleRequest()
ResponseStatusCode: 400
Client-Code
I set a token in the HTTP-Request-Header...
/// <summary>
/// Initializes a new instance of the <see cref="ServiceBase"/> class.
/// </summary>
/// <param name="uri">service uri</param>
protected ServiceBase(Uri uri)
{
this.Context = new Entities(uri) { MergeOption = MergeOption.OverwriteChanges };
this.Context.SendingRequest += new EventHandler<SendingRequestEventArgs>(this.ContextSendingRequest);
}
/// <summary>
/// OnSendingRequest
/// </summary>
/// <param name="sender">source</param>
/// <param name="e">event args</param>
private void ContextSendingRequest(object sender, SendingRequestEventArgs e)
{
e.RequestHeaders["token"] = "xyassdfdfdfdf";
}
Service-Code:
The Service parses this Header and checks the token
public XYDataService()
{
this.ProcessingPipeline.ProcessingRequest += this.ProcessingPipelineProcessingRequest;
}
/// <summary>
/// OnProcessingRequest
/// </summary>
/// <param name="sender">source</param>
/// <param name="e">event args</param>
private void ProcessingPipelineProcessingRequest(object sender, DataServiceProcessingPipelineEventArgs e)
{
var authHeader = HttpContext.Current.Request.Headers["token"];
if (string.IsNullOrEmpty(authHeader) || !authHeader.Equals("xyassdfdfdfdf"))
{
throw new DataServiceException(401, "401 Unauthorized");
}
}
Thanks for your help.
Andi

Using answer since I need to put more text here.
I tried a very similar code to yours, but it works just fine:
DemoService ctx = new DemoService(new Uri("http://services.odata.org/(S(jcemln1vp0u1gqtoyqqpwrc1))/OData/OData.svc/"));
ctx.UsePostTunneling = true;
ctx.SendingRequest += (sender, ea) => { ea.RequestHeaders["token"] = "value"; };
ctx.UpdateObject(ctx.Products.First());
ctx.SaveChanges();
Running this using the latest WCF DS 5.0 bits from NuGet works. I also verified with Fiddler that it does send the Content-Type header.
Your request on the other hand doesn't have the Content-Type header. Can you please verify that you're using the latest NuGet packages and that the code you posted above is really what you're testing?

Related

how to call my api qnamaker using Microsoft.Azure.CognitiveServices.Knowledge.QnAMaker nuget version 1.0.0

I am getting started with Microsoft.Azure.CognitiveServices.Knowledge.QnAMaker nuget,
and I am trying to use QnAMakerClient() class to initialise a new instance of the QNAMakerClient class.
But this class takes abstract parameters :
public QnAMakerClient(ServiceClientCredentials credentials, params DelegatingHandler[] handlers).
I found some solution
https://csharp.hotexamples.com/examples/Microsoft.Rest/TokenCredentials/-/php-tokencredentials-class-examples.html which indicates how to get the credentials token.
As I am new to this concept, so I don't know how to get credentials token for my ServiceClientCredentials.
You can create your own TokenCredentials class which inherit from ServiceClientCredentials as shown below:
public class TokenCredentials : ServiceClientCredentials
{
/// <summary>
/// The bearer token type, as serialized in an http Authentication header.
/// </summary>
private const string BearerTokenType = "Bearer";
/// <summary>
/// Gets or sets secure token used to authenticate against Microsoft Azure API.
/// No anonymous requests are allowed.
/// </summary>
protected ITokenProvider TokenProvider { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="TokenCredentials"/>
/// class with the given 'Bearer' token.
/// </summary>
/// <param name="token">Valid JSON Web Token (JWT).</param>
public TokenCredentials(string token)
: this(token, BearerTokenType)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="TokenCredentials"/>
/// class with the given token and token type.
/// </summary>
/// <param name="token">Valid JSON Web Token (JWT).</param>
/// <param name="tokenType">The token type of the given token.</param>
public TokenCredentials(string token, string tokenType)
: this(new StringTokenProvider(token, tokenType))
{
if (string.IsNullOrEmpty(token))
{
throw new ArgumentNullException("token");
}
if (string.IsNullOrEmpty(tokenType))
{
throw new ArgumentNullException("tokenType");
}
}
/// <summary>
/// Create an access token credentials object, given an interface to a token source.
/// </summary>
/// <param name="tokenProvider">The source of tokens for these credentials.</param>
public TokenCredentials(ITokenProvider tokenProvider)
{
if (tokenProvider == null)
{
throw new ArgumentNullException("tokenProvider");
}
this.TokenProvider = tokenProvider;
}
/// <summary>
/// Apply the credentials to the HTTP request.
/// </summary>
/// <param name="request">The HTTP request.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>
/// Task that will complete when processing has completed.
/// </returns>
public async override Task ProcessHttpRequestAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
if (request == null)
{
throw new ArgumentNullException("request");
}
if (TokenProvider == null)
{
throw new InvalidOperationException(Resources.TokenProviderCannotBeNull);
}
request.Headers.Authorization = await TokenProvider.GetAuthenticationHeaderAsync(cancellationToken);
await base.ProcessHttpRequestAsync(request, cancellationToken);
}
}
This is a good starting point for knowing more about QnAMaker.
Hope this helps!!!

Asp.Net Core with redis implementation gives 502 Error for high traffic

In Our application, we are having heavy traffic of users and it is around 2000 request per second.
We have created application in Asp.Net core and used dapper. We are using redis cache manager for distibuted caching purpose.
When we hosted this site and checked it for few (20 or 30) request per second, it was working fine. But when we are hitting more than around 50 requests per second, site is giving
502 - Web server received an invalid response while acting as a gateway or proxy server.
We changed redis caching to memory cache and then it started to work fine for all 2000 request s per second.
We are using redis version 3.2.100
So, here using redis we are not able to run this site for more requests and getting 502 error with heavy traffic.
Code written for Redis Cache
using Common;
using Common.DependencyInjection;
using Newtonsoft.Json;
using StackExchange.Redis;
using System;
using System.Text;
namespace Service.Caching
{
[TransientDependency(ServiceType = typeof(ICacheManager))]
public class RedisCacheManager : ICacheManager
{
private readonly string _redisHost;
private readonly int _redisPort;
private readonly string _redisPassword;
private readonly ConfigurationOptions _configurationOptions;
public RedisCacheManager()
{
_redisHost = ConfigItems.RedisHost;
_redisPassword = ConfigItems.RedisPassword;
_redisPort = ConfigItems.RedisPort;
_configurationOptions = new ConfigurationOptions();
configurationOptions.EndPoints.Add(_redisHost, redisPort);
_configurationOptions.Ssl = false;
//_configurationOptions.Password = _redisPassword;
_configurationOptions.AbortOnConnectFail = false;
_configurationOptions.SyncTimeout = int.MaxValue;
_configurationOptions.DefaultVersion = new Version(2, 8, 8);
_configurationOptions.WriteBuffer = 10000000;
_configurationOptions.KeepAlive = 180;
}
/// <summary>
/// Gets or sets the value associated with the specified key.
/// </summary>
/// <typeparam name="T">Type</typeparam>
/// <param name="key">The key of the value to get.</param>
/// <returns>
/// The value associated with the specified key.
/// </returns>
public T Get<T>(string key)
{
using (var connection = ConnectionMultiplexer.Connect(_configurationOptions))
{
var db = connection.GetDatabase(-1);
//return (T)(object)db.StringGet(key);
return (T)ConvertToObject<T>(db.StringGet(key));
}
}
/// <summary>
/// Adds the specified key and object to the cache.
/// </summary>
/// <param name="key">key</param>
/// <param name="data">Data</param>
/// <param name="cacheTime">Cache time</param>
public void Set(string key, object data, int cacheTime)
{
if (data == null)
return;
DateTime expireDate;
if (cacheTime == 99)
expireDate = DateTime.Now + TimeSpan.FromSeconds(30);
else
expireDate = DateTime.Now + TimeSpan.FromMinutes(cacheTime);
var value = (RedisValue)ConvertToByteArray(data);
using (var connection = ConnectionMultiplexer.Connect(_configurationOptions))
{
var db = connection.GetDatabase(-1);
db.StringSet(key, value, new TimeSpan(expireDate.Ticks));
}
}
/// <summary>
/// Gets a value indicating whether the value associated with the specified key is cached
/// </summary>
/// <param name="key">key</param>
/// <returns>
/// Result
/// </returns>
public bool IsSet(string key)
{
using (var connection = ConnectionMultiplexer.Connect(_configurationOptions))
{
var db = connection.GetDatabase(-1);
return db.KeyExists(key);
}
}
/// <summary>
/// Removes the value with the specified key from the cache
/// </summary>
/// <param name="key">/key</param>
public void Remove(string key)
{
using (var connection = ConnectionMultiplexer.Connect(_configurationOptions))
{
var db = connection.GetDatabase(-1);
db.KeyDelete(key);
}
}
/// <summary>
/// Removes items by pattern
/// </summary>
/// <param name="pattern">pattern</param>
public void RemoveByPattern(string pattern)
{
using (var connection = ConnectionMultiplexer.Connect(_configurationOptions))
{
var server = connection.GetServer(_redisHost, _redisPort);
var keysToRemove = server.Keys(pattern: "*" + pattern + "*");//-1, pattern);
foreach (var key in keysToRemove)
Remove(key);
}
}
/// <summary>
/// Clear all cache data
/// </summary>
public void Clear()
{
using (var connection = ConnectionMultiplexer.Connect(_configurationOptions))
{
var server = connection.GetServer(_redisHost, _redisPort);
//var keysToRemove = server.Keys(-1);
var keysToRemove = server.Keys();
foreach (var key in keysToRemove)
Remove(key);
}
}
/// <summary>
/// Converts to byte array.
/// </summary>
/// <param name="data">The data.</param>
/// <returns>System.Byte[].</returns>
private byte[] ConvertToByteArray(object data)
{
if (data == null)
return null;
string serialize = JsonConvert.SerializeObject(data);
return Encoding.UTF8.GetBytes(serialize);
}
/// <summary>
/// Converts to object.
/// </summary>
/// <param name="data">The data.</param>
/// <returns>System.Object.</returns>
private T ConvertToObject<T>(byte[] data)
{
try
{
return JsonConvert.DeserializeObject<T>(Encoding.UTF8.GetString(data));
}
catch (Exception ex)
{
return (T)Activator.CreateInstance(typeof(T));
}
}
}
}
Your calls to Getting / Setting / Removing keys / values from the Redis cache might be taking longer as you are creating a new ConnectionMultiplexer on each operation to Redis.
https://gist.github.com/JonCole/925630df72be1351b21440625ff2671f#file-redis-bestpractices-stackexchange-redis-md has some best practices while using StackExchange.Redis.
https://learn.microsoft.com/en-us/azure/redis-cache/cache-dotnet-how-to-use-azure-redis-cache#connect-to-the-cache shows the recommended usage pattern.
Also, look at the StackExchange.Redis documentation (https://stackexchange.github.io/StackExchange.Redis/Basics) which says "ecause the ConnectionMultiplexer does a lot, it is designed to be shared and reused between callers. You should not create a ConnectionMultiplexer per operation. It is fully thread-safe and ready for this usage. In all the subsequent examples it will be assumed that you have a ConnectionMultiplexer instance stored away for re-use".

Silverlight is not liking my WCF MessageContract. Why?

I am attempting to upload a file through a Silverlight client using the following MessageContract:
[MessageContract]
public class CategoryClientFileTransferMC : IDisposable
{
/// <summary>
/// CategoryID - Category identity.
/// </summary>
[MessageHeader(MustUnderstand = true)]
public int CategoryID;
/// <summary>
/// ID - File identifier.
/// </summary>
[MessageHeader(MustUnderstand = true)]
public string ID;
/// <summary>
/// Length - File length in bytes.
/// </summary>
[MessageHeader(MustUnderstand = true)]
public long Length;
/// <summary>
/// FileByteStream - File stream.
/// </summary>
[MessageBodyMember(Order = 1)]
public Stream FileByteStream;
/// <summary>
/// Dispose the contract.
/// </summary>
public void Dispose()
{
if (FileByteStream != null)
{
FileByteStream.Close();
FileByteStream = null;
}
}
}
My problem is that the generated operation method on the client only takes a single argument; a byte array called FileByteStream. In other (non-Silverlight) clients I've created it asks for the MemberHeader fields as well. Without specifying these headers, the server has no idea what to do with the file. How can I set these headers when I call the operation?
Also, is there a better way to upload a file from a Silverlight client? This has been a huge headache.
Thanks.
The Silverlight subset of the WCF client does not support the [MessageHeader] attribute. You can still set message headers, but it's not as straightforward as in other platforms. Basically, you'll need to set the headers using the operation context, prior to making the call, like in the example below:
var client = new SilverlightReference1.MyClient();
using (new OperationContextScope(client.InnerChannel))
{
string contractNamespace = "http://tempuri.org/";
OperationContext.Current.OutgoingMessageHeaders.Add(
MessageHeader.CreateHeader("CategoryId", contractNamespace, 1));
OperationContext.Current.OutgoingMessageHeaders.Add(
MessageHeader.CreateHeader("ID", contractNamespace, "abc123"));
OperationContext.Current.OutgoingMessageHeaders.Add(
MessageHeader.CreateHeader("Length", contractNamespace, 123456L));
client.UploadFile(myFileContents);
}
Where contractNamespace is the XML namespace for the message header fields (IIRC they default to the same as the service contract). You can use Fiddler and something like the WCF Test Client to see which namespace is used there.

Workflow services scalability issue

I'm currently experiencing some issues with workflow services.
They work fine if I start 4, 5 in short sequence, but if I increase this value (starting from ~10) then I get the following exception:
This channel can no longer be used to send messages as the output session was auto-closed due to a server-initiated shutdown. Either disable auto-close by setting the DispatchRuntime.AutomaticInputSessionShutdown to false, or consider modifying the shutdown protocol with the remote server.
I think that the problem is in the way I create proxies. I use the following code to provide proxies, attempting to reuse existing ones:
public abstract class ProxyProvider<TService>
where TService : class
{
/// <summary>
/// Static reference to the current time provider.
/// </summary>
private static ProxyProvider<TService> current = DefaultProxyProvider.Instance;
private TService service;
/// <summary>
/// Gets or sets the current time provider.
/// </summary>
/// <value>
/// The current time provider.
/// </value>
public static ProxyProvider<TService> Current
{
get
{
return ProxyProvider<TService>.current;
}
set
{
if (value == null)
{
throw new ArgumentNullException("value");
}
ProxyProvider<TService>.current = value;
}
}
/// <summary>
/// Resets to default.
/// </summary>
public static void ResetToDefault()
{
ProxyProvider<TService>.current = DefaultProxyProvider.Instance;
}
/// <summary>
/// Loads the proxy.
/// </summary>
/// <param name="forceNew">if set to <c>true</c> [force new].</param>
/// <returns>The instance of the proxy.</returns>
public virtual TService Provide(bool forceNew = false)
{
if (forceNew || !this.IsInstanceValid())
{
this.service = this.CreateInstance();
return this.service;
}
return this.service;
}
/// <summary>
/// Internals the load.
/// </summary>
/// <returns>The new created service.</returns>
protected abstract TService CreateInstance();
private bool IsInstanceValid()
{
var instance = this.service as ICommunicationObject;
if (instance == null)
{
return false;
}
return instance.State != CommunicationState.Faulted && instance.State != CommunicationState.Closed && instance.State != CommunicationState.Closing;
}
/// <summary>
/// Defines the default <see cref="ProxyProvider<TService>"/> which uses the System DateTime.UtcNow value.
/// </summary>
private sealed class DefaultProxyProvider : ProxyProvider<TService>
{
/// <summary>
/// Reference to the instance of the <see cref="ProxyProvider<TService>"/>.
/// </summary>
private static ProxyProvider<TService> instance;
/// <summary>
/// Gets the instance.
/// </summary>
public static ProxyProvider<TService> Instance
{
get
{
if (DefaultProxyProvider.instance == null)
{
DefaultProxyProvider.instance = new DefaultProxyProvider();
}
return DefaultProxyProvider.instance;
}
}
/// <summary>
/// Loads the specified force new.
/// </summary>
/// <returns>A non-disposed instance of the given service.</returns>
protected override TService CreateInstance()
{
var loadedService = Activator.CreateInstance<TService>();
return loadedService;
}
}
With an additional "lazy" provider:
public class CustomConstructorProxyProvider<TService> : ProxyProvider<TService>
where TService : class
{
private readonly Func<TService> constructor;
/// <summary>
/// Initializes a new instance of the <see cref="CustomConstructorProxyProvider<TService>"/> class.
/// </summary>
/// <param name="constructor">The constructor.</param>
public CustomConstructorProxyProvider(Func<TService> constructor)
{
this.constructor = constructor;
}
/// <summary>
/// Internals the load.
/// </summary>
/// <returns>The new created service.</returns>
protected override TService CreateInstance()
{
var service = this.constructor();
return service;
}
}
Used this way:
var proxy = ProxyProvider<IWorkflowService>.Current.Provide();
proxy.DoSomething();
Initialized like this:
ProxyProvider<IWorkflowService>.Current = new CustomConstructorProxyProvider<IWorkflowService>(() => new WorkflowServiceProxy("endpoint"));
Workflow services are hosted by IIS and I added the following throttling settings:
<serviceThrottling
maxConcurrentCalls="512"
maxConcurrentInstances="2147483647"
maxConcurrentSessions="1024"/>
which should be enough for my needs.
I hope that someone can help me configuring client and server to have achieve the desired scalability (a few hundreds started in sequence and running in parallel, using the WorkflowInstance sql store).
UPDATE:
I'm using NetTcpBinding for all services.
UPDATE 2:
All services are hosted and consumed by now locally.
Thanks
Francesco

How to intercept SOAP messages

As part of my venture into WCF I'm looking at message contracts and seeing how they affect the content of the SOAP message.
What would be really cool is if you could intercept the message and see how it is structured. How would I go about doing this please...
(So far I've looked at Wireshark (too 'low-level') and thought about Microsoft SOAP toolkit but this was retired by microsoft back in 2005)
When you installed .NET 3.5 or up, you should have the WCF Test Client on your machine somewhere (hidden deep inside a directory like C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\ or something like that).
This tool allows you to connect to your WCF service, and you can call methods on it - and you can look at the XML request and response in all its beauty :-)
The other option would be to use something like the free version of SoapUI which is designed to test SOAP services and show request and response in XML
SoapUI is a great tool - but it's not WCF specific, it's just a "generic" SOAP/WSDL tool which works great against any SOAP service.
If you're not looking for "on-demand" capturing of requests and responses, but if you're more interested in having a trace of all requests and responses, you should investigate the WCF tracing features and setup them up as needed. You can capture all traffic into a *.svclog file on disk, and there's the WCF Service Trace Viewer (also free with WCF) to inspect those trace files.
I usually use Fiddler to inspect soap messages sent over http.
If you want to write a log record is try using TraceExtension class, below an example,
in this link you will find details about how to implement it, I use it and it worked very well
http://www.systemdeveloper.info/2013/11/trace-soap-requestresponse-xml-with.html
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Services.Protocols;
using System.IO;
using System.Xml;
namespace PruebaServiciosNBC
{
class TraceExtension : SoapExtension
{
private Stream oldStream;
private Stream newStream;
private static XmlDocument xmlRequest;
/// <summary>
/// Gets the outgoing XML request sent to PayPal
/// </summary>
public static XmlDocument XmlRequest
{
get { return xmlRequest; }
}
private static XmlDocument xmlResponse;
/// <summary>
/// Gets the incoming XML response sent from PayPal
/// </summary>
public static XmlDocument XmlResponse
{
get { return xmlResponse; }
}
/// <summary>
/// Save the Stream representing the SOAP request
/// or SOAP response into a local memory buffer.
/// </summary>
/// <param name="stream">
/// <returns></returns>
public override Stream ChainStream(Stream stream)
{
oldStream = stream;
newStream = new MemoryStream();
return newStream;
}
/// <summary>
/// If the SoapMessageStage is such that the SoapRequest or
/// SoapResponse is still in the SOAP format to be sent or received,
/// save it to the xmlRequest or xmlResponse property.
/// </summary>
/// <param name="message">
public override void ProcessMessage(SoapMessage message)
{
switch (message.Stage)
{
case SoapMessageStage.BeforeSerialize:
break;
case SoapMessageStage.AfterSerialize:
xmlRequest = GetSoapEnvelope(newStream);
CopyStream(newStream, oldStream);
break;
case SoapMessageStage.BeforeDeserialize:
CopyStream(oldStream, newStream);
xmlResponse = GetSoapEnvelope(newStream);
break;
case SoapMessageStage.AfterDeserialize:
break;
}
}
/// <summary>
/// Returns the XML representation of the Soap Envelope in the supplied stream.
/// Resets the position of stream to zero.
/// </summary>
/// <param name="stream">
/// <returns></returns>
private XmlDocument GetSoapEnvelope(Stream stream)
{
XmlDocument xml = new XmlDocument();
stream.Position = 0;
StreamReader reader = new StreamReader(stream);
xml.LoadXml(reader.ReadToEnd());
stream.Position = 0;
return xml;
}
/// <summary>
/// Copies a stream.
/// </summary>
/// <param name="from">
/// <param name="to">
private void CopyStream(Stream from, Stream to)
{
TextReader reader = new StreamReader(from);
TextWriter writer = new StreamWriter(to);
writer.WriteLine(reader.ReadToEnd());
writer.Flush();
}
#region NoOp
/// <summary>
/// Included only because it must be implemented.
/// </summary>
/// <param name="methodInfo">
/// <param name="attribute">
/// <returns></returns>
public override object GetInitializer(LogicalMethodInfo methodInfo,
SoapExtensionAttribute attribute)
{
return null;
}
/// <summary>
/// Included only because it must be implemented.
/// </summary>
/// <param name="WebServiceType">
/// <returns></returns>
public override object GetInitializer(Type WebServiceType)
{
return null;
}
/// <summary>
/// Included only because it must be implemented.
/// </summary>
/// <param name="initializer">
public override void Initialize(object initializer)
{
}
#endregion NoOp
}
}