Is it possible to make servicestack use an unbuffered response stream? - iis

I want to send messages back to a client via a stream. I want the client to start processing these messages as soon as possible (before the server has completed the streaming on the server side).
I have implemented IStreamWriter and I have a service which returns the IStreamWriter implementation.
public class StreamingService : Service
{
public object Any(MyStreamRequest request)
{
return new MyStreamWriter(request);
}
}
Where MyStreamRequest is defined like this:
[DataContract]
public class StreamRequest : IReturn<Stream>
{
[DataMember]
public int HowManySecondsToProduceData { get; set; }
}
When I test my implementation in a self-hosted environment it works perfectly. However, when I host this in IIS, the get call from the client
var client = new ProtoBufServiceClient("");
Stream stream = client.Get(new StreamRequest { HowManySecondsToProduceData = 20};
does not return until the IStreamWriter.WriteTo call returns (20 seconds in the sample above). This prevents my client from processing the stream right away and will also cause failure in high volume cases. I do call responseStream.Flush() inside my IStreamWriter.WriteTo implementation.
Does anybody have any insight on why this does not work in the IIS scenario, but only for the self hosted case? What do I need to do differently?
It seems like a likely cause of this problem is that the servicestack response stream is set to use buffering. I cannot find a way to change this though. Is it possible?

You just need to disable ASP.Nets response buffering:
public class NoBufferAttribute : RequestFilterAttribute
{
public override void Execute( IHttpRequest req, IHttpResponse res, object requestDto )
{
var originalResponse = (System.Web.HttpResponse)res.OriginalResponse;
originalResponse.BufferOutput = false;
}
}
John

I found a solution myself: The solution to this problem is quite simple: Call IHttpResponse Flush() inside the IStreamWriter.WriteTo implementation when you want to send data to the client. You get the IHttpResponse by calling base.Response inside the Service implementation.

Related

ArchUnit: Verify method only calls one outside method

In a Controller-Service-Datalayer architecture, I'm searching for a way to verify that my controller methods perform exactly one call to the service layer like this:
#DeleteMapping(value = "/{id}")
public ResponseEntity<String> deleteBlubber(#PathVariable("id") long blubberId) {
service.deleteBlubber(blubberId);
return new ResponseEntity<>("ok", HttpStatus.OK);
}
This should not be allowed:
#DeleteMapping(value = "/{id}")
public ResponseEntity<String> deleteBlubber(#PathVariable("id") long blubberId) {
service.deleteOtherStuffFirst(); // Opens first transaction
service.deleteBlubber(blubberId); // Opens second transaction - DANGER!
return new ResponseEntity<>("ok", HttpStatus.OK);
}
As you can see from the comments, the reason for this is to make sure that each request is handled in one transaction (that is started in the service layer), not multiple transactions.
It seems that ArchUnit can only check meta-data from classes and methods and not what's actually going on in a method. I would have to be able to count the request to the service classes, which seems to not be possible in ArchUnit.
Any idea if this might be possible? Thanks!
With JavaMethod.getMethodCallsFromSelf() you have access to all methods calls of a given method. This could be used inside a custom ArchCondition like this:
methods()
.that().areDeclaredInClassesThat().areAnnotatedWith(Controller.class)
.should(new ArchCondition<JavaMethod>("call exactly one service method") {
#Override
public void check(JavaMethod item, ConditionEvents events) {
List<JavaMethodCall> serviceCalls = item.getMethodCallsFromSelf().stream()
.filter(call -> call.getTargetOwner().isAnnotatedWith(Service.class))
.toList();
if (serviceCalls.size() != 1) {
String message = serviceCalls.stream().map(JavaMethodCall::getDescription).collect(joining(" and "));
events.add(SimpleConditionEvent.violated(item, message));
}
}
})

Is it possible to exclude a url from Application Insights?

We have an Azure web role deployed that has been using Application Insights (ver. 1.0.0.4220), however, we're going over our data quota. Is it possible to configure Application Insights ignore a specific URL?
We have a status web service that gets a huge amount of traffic but never throws any errors. If I could exclude this one service URL I could cut my data usage in half.
Out of the box it is not supported. Sampling feature is coming but that would not be configurable by specific url. You can implement your own channel that would have your custom filtering. Basically your channel will get event to be sent, you check if you want to send it or not and then if yes pass to standard AI channel. Here you can read more about custom channels.
There are two things that changed since this blog post has been written:
channel should implement only ITelemetryChannel interface (ISupportConfiguration was removed)
and instead of PersistenceChannel you should use Microsoft.ApplicationInsights.Extensibility.Web.TelemetryChannel
UPDATE: Latest version has filtering support: https://azure.microsoft.com/en-us/blog/request-filtering-in-application-insights-with-telemetry-processor/
My team had a similiar situation where we needed to filter out urls that were successful image requests (we had a lot of these which made us hit the 30k datapoints/min limit).
We ended up using a modified version of the class in Sergey Kanzhelevs blog post to filter these out.
We created a RequestFilterChannel class which is an instance of ServerTelemetryChannel and extended the Send method. In this method we test each telemetry item to be sent to see if it is an image request and if so, we prevent it from being sent.
public class RequestFilterChannel : ITelemetryChannel, ITelemetryModule
{
private ServerTelemetryChannel channel;
public RequestFilterChannel()
{
this.channel = new ServerTelemetryChannel();
}
public void Initialize(TelemetryConfiguration configuration)
{
this.channel.Initialize(configuration);
}
public void Send(ITelemetry item)
{
if (item is RequestTelemetry)
{
var requestTelemetry = (RequestTelemetry) item;
if (requestTelemetry.Success && isImageRequest((RequestTelemetry) item))
{
// do nothing
}
else
{
this.channel.Send(item);
}
}
else
{
this.channel.Send(item);
}
}
public bool? DeveloperMode
{
get { return this.channel.DeveloperMode; }
set { this.channel.DeveloperMode = value; }
}
public string EndpointAddress
{
get { return this.channel.EndpointAddress; }
set { this.channel.EndpointAddress = value; }
}
public void Flush()
{
this.channel.Flush();
}
public void Dispose()
{
this.channel.Dispose();
}
private bool IsImageRequest(RequestTelemetry request)
{
if (request.Url.AbsolutePath.StartsWith("/image.axd"))
{
return true;
}
return false;
}
}
Once the class has been created you need to add it to your ApplicationInsights.config file.
Replace this line:
<TelemetryChannel Type="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel.ServerTelemetryChannel, Microsoft.AI.ServerTelemetryChannel"/>
with a link to your class:
<TelemetryChannel Type="XXX.RequestFilterChannel, XXX" />
Alternatively, you can disable the automated request collection and keep only exception auto-collection, just remove the RequestTrackingModule line from applicationinsights.config.
If you still need to collect some of the requests, not just filter all out, you can then call TrackRequest() (in the object of TelemetryClient class) from your code in the appropriate place after you know that you certainly need to log this request to AI.
Update: Filtering feature has been released some time ago and allows for exclusion of certain telemetry items way easier.

Why is my call to Azure killing HttpContext.Current

I have an MVC application in which I have a controller that receives data from the user and then uploads a file to Azure blob storage. The application is using Unity IoC to handle dependency injection.
During the workflow I have isolated the following code as demonstrating the problem
public class MvcController : Controller
{
private IDependencyResolver _dependencyResolver;
public MvcController() : this(DependencyResolver.Current)
{
}
public MvcController(IDependencyResolver dependencyResolver)
{
this._dependencyResolver = dependencyResolver;
}
public GetService<T>()
{
T resolved = _dependencyResolver.GetService<T>()
if (resolved == null)
throw new Exception(string.Format("Dependency resolver does not contain service of type {0}", typeof(T).Name));
return resolved;
}
}
public class MyController : MvcController
{
[NoAsyncTimeout]
public async Task<ActionResult> SaveFileAsync(/* A bunch of arguments */)
{
/* A bunch of code */
//This line gets a concrete instance from HttpContext.Current successfully...
IMyObject o = GetService<IMyObject>();
await SaveFileToAzure(/* A bunch of parameters */);
.
.
/* Sometime later */
Method2(/* A bunch of parameters */);
}
private Method2(/* A bunch of parameters */)
{
//This line fails because HttpContext.Current is null
IMyObject o = GetService<IMyObject>();
/* A bunch of other code */
}
private async Task SaveFileToAzure(/* A bunch of parameters */)
{
//Grab a blob container to store the file data...
CloudBlobContainer blobContainer = GetBlobContainer();
ICloudBlob blob = blobContainer.GetBlockBlobReference(somePath);
Stream dataStream = GetData();
System.Threading.CancellationToken cancelToken = GetCancellationToken();
//All calls to DependencyResolver.GetService<T>() after this line of code fail...
response = await blob.UploadStreamAsync(dataStream, cancelToken);
/* A bunch of other code */
}
}
Unity has a registration for my object:
container.RegisterType<IMyObject, MyObject>(new HttpLifetimeManager());
My lifetime manager is defined as follows:
public sealed class HttpRequestLifetimeManager : LifetimeManager
{
public Guid Key { get; private set; }
public HttpRequestLifetimeManager()
{
this.Key = Guid.NewGuid();
}
public override object GetValue()
{
return HttpContext.Current.Items[(object)this.Key];
}
public override void SetValue(object newValue)
{
HttpContext.Current.Items[(object)this.Key] = newValue;
}
public override void RemoveValue()
{
HttpContext.Current.Items.Remove((object)this.Key);
}
}
Nothing complicated.
Stepping into the HttpRequestLifetimeManager on the failing GetService() calls shows that after the UploadStreamAsync() call HttpContext.Current is null...
Has anyone else come across this problem? If so, is this a bug? Is this expected behaviour? Am I doing something out of the ordinary? What should I do to resolve it?
I can hack around it by storing a reference to HttpContext.Current prior to the offending call and restoring it after, but that doesn't seem like the right approach.
Any ideas?
To echo #Joachim - http context may not be available to your async thread. Compare the current thread id where you can see httpcontext is available, to the thread id where you can see that it isn't - i'm assuming you will see they are 2 different threads. If my assumption is correct this may be a sign that your main thread (the one with httpcontext) does not have a "synchronizationcontext". (you can see http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx for more details of how that works) If so, it may mean that the code immediately after your await statement is actually not running on the same thread as the code prior to the await statement! So from your perspective, one moment you have http context and the next you don't because execution has actually been switched to another thread! You should probably look at implementing / setting a synchronizationcontext on your main thread if that's the case and then control will be returned to your original thread with http context and that should fix your problem, or alternatively you could retrieve your object from http context on the original thread and find a way to pass it as a parameter to the async method/s so that they don't need to access http context to get their state.

Enable gzip/deflate compression

I'm using ServiceStack (version 3.9.44.0) as a Windows Service (so I'm not using IIS) and I use both its abilities both as an API and for serving web pages.
However, I haven't been able to find how exactly I should enable compression when the client supports it.
I imagined that ServiceStack would transparently compress data if the client's request included the Accept-Encoding:gzip,deflate header, but I'm not seeing any corresponding Content-Encoding:gzip in the returned responses.
So I have a couple of related questions:
In the context of using ServiceStack as a standalone service (without IIS), how do I enable compression for the responses when the browser accepts it.
In the context of a C# client, how do similarly I ensure that communication between the client/server is compressed.
If I'm missing something, any help would be welcome.
Thank you.
If you want to enable compression globally across your API, another option is to do this:
Add this override to your AppHost:
public override IServiceRunner<TRequest> CreateServiceRunner<TRequest>(ActionContext actionContext)
{
return new MyServiceRunner<TRequest>(this, actionContext);
}
Then implement that class like this:
public class MyServiceRunner<TRequest> : ServiceRunner<TRequest>
{
public MyServiceRunner(IAppHost appHost, ActionContext actionContext) : base(appHost, actionContext)
{
}
public override void OnBeforeExecute(IRequestContext requestContext, TRequest request)
{
base.OnBeforeExecute(requestContext, request);
}
public override object OnAfterExecute(IRequestContext requestContext, object response)
{
if ((response != null) && !(response is CompressedResult))
response = requestContext.ToOptimizedResult(response);
return base.OnAfterExecute(requestContext, response);
}
public override object HandleException(IRequestContext requestContext, TRequest request, Exception ex)
{
return base.HandleException(requestContext, request, ex);
}
}
OnAfterExecute will be called and give you the chance to change the response. Here, I am compressing anything that is not null and not already compressed (in case I'm using ToOptimizedResultUsingCache somewhere). You can be more selective if you need to but in my case, I'm all POCO objects with json.
References
ServiceStack New Api
For those interested, a partial answer to my own question, you can use the extension method ToOptimizedResult() or, if you are using caching ToOptimizedResultUsingCache().
For instance, returning a compressed result:
public class ArticleService : Service
{
public object Get(Articles request) {
return base.RequestContext.ToOptimizedResult(
new List<Articles> {
new Article {Ref = "SILVER01", Description = "Silver watch"},
new Article {Ref = "GOLD1547", Description = "Gold Bracelet"}
});
}
}
References
CachedServices.cs example
CompressedResult.cs
Google Group question on Compression in ServiceStack

Is it possible to inject an instance of object to service at runtime

I have created a plugin which inspects a param in the query string and loads up a user object based on this ID and populates
any request DTO with it. (All my request DTO's inherit from BaseRequest which has a CurrentUser property)
public class CurrentUserPlugin : IPlugin
{
public IAppHost CurrentAppHost { get; set; }
public void Register(IAppHost appHost)
{
CurrentAppHost = appHost;
appHost.RequestFilters.Add(ProcessRequest);
}
public void ProcessRequest(IHttpRequest request, IHttpResponse response, object obj)
{
var requestDto = obj as BaseRequest;
if (requestDto == null) return;
if (request.QueryString["userid"] == null)
{
throw new ArgumentNullException("No userid provided");
}
var dataContext = CurrentAppHost.TryResolve<IDataContext>();
requestDto.CurrentUser = dataContext.FindOne<User>(ObjectId.Parse(requestDto.uid));
if (requestDto.CurrentUser == null)
{
throw new ArgumentNullException(string.Format("User [userid:{0}] not found", requestDto.uid));
}
}
}
I need to have this User object available in my services but I don't want to inspect the DTO every time and extract from there. Is there a way to make data from plugins globally available to my services? I am also wondering if there is another way of instantiating this object as for my unit tests, the Plugin is not run - as I call my service directly.
So, my question is, instead of using Plugins can I inject a user instance to my services at run time? I am already using IoC to inject different Data base handlers depending on running in test mode or not but I can't see how to achieve this for User object which would need to be instantiated at the beginning of each request.
Below is an example of how I inject my DataContext in appHost.
container.Register(x => new MongoContext(x.Resolve<MongoDatabase>()));
container.RegisterAutoWiredAs<MongoContext, IDataContext>();
Here is an example of my BaseService. Ideally I would like to have a CurrentUser property on my service also.
public class BaseService : Service
{
public BaseService(IDataContext dataContext, User user)
{
DataContext = dataContext;
CurrentUser = user; // How can this be injected at runtime?
}
public IDataContext DataContext { get; private set; }
public User CurrentUser { get; set; }
}
Have you thought about trying to use the IHttpRequest Items Dictionary to store objects. You can access these Items from any filter or service or anywhere you can access IHttpRequest. See the src for IHttpRequest.
Just be mindful of the order that your attributes, services and plugins execute and when you store the item in the Items dictionary.
Adding:
We don't want to use HttpContext inside of the Service because we want use Service in our tests directly.
Advantages for living without it
If you don't need to access the HTTP
Request context there is nothing stopping you from having your same
IService implementation processing requests from a message queue which
we've done for internal projects (which incidentally is the motivation
behind the asynconeway endpoint, to signal requests that are safe for
deferred execution).
http://www.servicestack.net/docs/framework/accessing-ihttprequest
And we don't use http calls to run tests.
So our solution is:
public class UserService
{
private readonly IDataContext _dataContext;
public UserService(IDataContext dataContext)
{
_dataContext = dataContext;
}
public User GetUser()
{
var uid = HttpContext.Current.Request.QueryString["userId"];
return _dataContext.Get<User>(uid);
}
}
and
container.Register(x => new UserService(x.Resolve<IDataContext>()).GetUser()).ReusedWithin(ReuseScope.Request);
This is service signature:
public SomeService(IDataContext dataContext, User user) { }
Any suggestions?
I need to have this User object available in my services but I don't want to inspect the DTO every time and extract from there
How will your application know about the user if you're not passing the 'userid' in the querystring? Could you store the user data in the Session? Using a Session assumes the client is connected to your app and persists a Session Id (ss-id or ss-pid cookie in ServiceStack) in the client that can be looked up on the Server to get the 'session data'. If you can use the Session you can retrieve the data from your service doing something like
base.Session["UserData"] or base.SessionAs<User>();
Note: you will need to save your User data to the Session
Is there a way to make data from plugins globally available to my services? but I can't see how to achieve this for User object which would need to be instantiated at the beginning of each request.
This sounds like you want a global request filter. You're kind of already doing this but you're wrapping it into a Plugin.

Resources