How to get result from the Service, if task run asynchronously?
If a task is started synchronously in main thread, there is no problem:
Object result = serviceInstanceInActivity.callMethod();
But if the task runs in other thread, we have a problem:
void asyncMethodInService() {
new MyTask().execute();
}
class MyTask extends AsyncTask<Void, Void, Result> {
// implementation of the others methods
public void onPostExecute(Result result) {
// We need to send data to Activity here
}
}
Of Course, it's work via ServiceConnection. In usual class, I would use interfaces as callback, but if I do same here, the Activity instance will leaked in Service via callback.
So, what is recommended way to deliver data in this cases?
I would use LocalBroadcastManager to broadcast an Intent containing the result, so that any interested activities can register for and receive the broadcast when the service completes its task.
If the data is complex and is not practical to pack into an Intent, you need to get a bit creative. You should probably use a ContentProvider and put a content URI into the intent which the activities can then use to query for the result. Or you might be able to store the result on a static singleton (or on your application instance) and just have the activity retrieve the updated value when it receives the broadcast. It depends on your requirements.
Hope that helps!
Related
As a follow-up to this question, I wanted to understand how my invoking of a Service manually can be improved. This became longer than I wanted, but I feel the background info is needed.
When doing a pub/sub (broadcast), the normal sequence and flow in the Messaging API isn't used, and I instead get a callback when a pub/sub message is received, using IRedisClient, IRedisSubscription:
_subscription.OnMessage = (channel, msg) =>
{
onMessageReceived(ParseJsonMsgToPoco(msg));
};
The Action onMessageReceived will then, in turn, invoke a normal .NET/C# Event, like so:
protected override void OnMessageReceived(MyRequest request)
{
OnMyEvent?.Invoke(this, new RequestEventArgs(request));
}
This works, I get my request and all that, however, I would like it to be streamlined into the other flow, the flow in the Messaging API, meaning, the request finds its way into a Service class implementation, and that all normal boilerplate and dependency injection takes place as it would have using Messaging API.
So, in my Event handler, I manually invoke the Service:
private void Instance_OnMyEvent(object sender, RequestEventArgs e)
{
using (var myRequestService = HostContext.ResolveService<MyRequestService>(new BasicRequest()))
{
myRequestService.Any(e.Request);
}
}
and the MyRequestService is indeed found and Any called, and dependency injection works for the Service.
Question 1:
Methods such as OnBeforeExecute, OnAfterExecute etc, are not called, unless I manually call them, like: myRequestService.OnBeforeExecute(e) etc. What parts of the pipeline is lost? Can it be reinstated in some easy way, so I don't have to call each of them, in order, manually?
Question 2:
I think I am messing up the DI system when I do this:
using (var myRequestService = HostContext.ResolveService<MyRequestService>(new BasicRequest()))
{
myRequestService.OnBeforeExecute(e.Request);
myRequestService.Any(e.Request);
myRequestService.OnAfterExecute(e.Request);
}
The effect I see is that the injected dependencies that I have registered with container.AddScoped, isn't scoped, but seems static. I see this because I have a Guid inside the injected class, and that Guid is always the same in this case, when it should be different for each request.
container.AddScoped<IRedisCache, RedisCache>();
and the OnBeforeExecute (in a descendant to Service) is like:
public override void OnBeforeExecute(object requestDto)
{
base.OnBeforeExecute(requestDto);
IRedisCache cache = TryResolve<IRedisCache>();
cache?.SetGuid(Guid.NewGuid());
}
So, the IRedisCache Guid should be different each time, but it isn't. This however works fine when I use the Messaging API "from start to finish". It seems that if I call the TryResolve in the AppHostBase descendant, the AddScoped is ignored, and an instance is placed in the container, and then never removed.
What parts of the pipeline is lost?
None of the request pipeline is executed:
myRequestService.Any(e.Request);
Is physically only invoking the Any C# method of your MyRequestService class, it doesn't (nor cannot) do anything else.
The recommended way for invoking other Services during a Service Request is to use the Service Gateway.
But if you want to invoke a Service outside of a HTTP Request you can use the RPC Gateway for executing non-trusted services as it invokes the full Request Pipeline & converts HTTP Error responses into Typed Error Responses:
HostContext.AppHost.RpcGateway.ExecuteAsync()
For executing internal/trusted Services outside of a Service Request you can use HostContext.AppHost.ExecuteMessage as used by ServiceStack MQ which applies Message Request Request/Response Filters, Service Action Filters & Events.
I have registered with container.AddScoped
Do not use Request Scoped dependencies outside of a HTTP Request, use Singleton if the dependencies are ThreadSafe, otherwise register them as Transient. If you need to pass per-request storage pass them in IRequest.Items.
Hello i am trying to do a trail log for some of my API endpoints.These logs are generated when the endpoint is called.I would like the writing of the logs to be done in an asynchrouns manner (as lightweight as possible) as to not affect the performance of my usual logic.
I was thinking to have a component that is injectable and can be called anywhere in my endpoints when a log is produced.The problem is that i seem to not find a suitable async solution:
Important service that needs not be obstructed by delays
public interface IImportantInterface
{
Task DoSomethingUndistrubedAsync(string value);
}
**Wrapper around Redis pub-sub**
public interface IIOService{
Task PublishAsync( object obj);
}
Controller
public class Controller
{
private IImportantInterface importantService;
private Publisher publisher;
[HttpPost]
public async Task SomeEndpointAsync(){
this.publisher.Publish([some_log]);
await this.importantService.DoSomethingUndisturbedAsync([something]);
}
public Controller(IImportantInterface importantService)
{
this.importantService=importantService;
}
}
Now comes the real problem.How do i make the smallest footprint for my Publisher.I came up with 3 scenarios but two of them are unfeasible due to going out of scope:
Attempt 1
Transient Service with Task scoped to method:
public class Publisher{
private IIOService writeService{get;set;}
public async Task PublishAsync(object obj){
Task t1=Task.Run(async()=>await writeService.PublishAsync(obj)); //t1 might not finished when method exits
}
}
Task t1 might not finish by the time the method ends.
Attempt 2
Task embedded in Transient Service
public class Publisher{ //publisher might get discarded when calling controller gets out of scope
private Task t1;
private IIOService writeService{get;set;}
public async Task PublishAsync(object obj){
t1=Task.Run(async ()=> this.IIOService.writeService(obj));
}
}
Now task will not get collected after method scope , but it might not finish by the time the calling Controller method class gets out of scope
Attempt 3
Singleton object with a ConcurrentQueue of Tasks that get enqueued.
This would not get out of scope but when would i clear the items?
public class Publisher{
private ConcurrentQueue<Task> Queue;
public async Task PublishAsync(object obj){
this.Queue.Enqueue();
}
}
P.S I want to publish these logs in a common place.From that place the target is to get published to a Redis database using the pub-sub functionality.
Should i just write to Redis ?
Hello i am trying to do a trail log for some of my API endpoints.These logs are generated when the endpoint is called.I would like the writing of the logs to be done in an asynchrouns manner (as lightweight as possible) as to not affect the performance of my usual logic.
I strongly recommend that you use an existing and exhaustively-tested logging library, of which there are many with modern capabilities such as semantic logging and async-compatible implicit state.
Modern logging libraries generally have a singleton kind of design, where logs are kept in-memory (and logging methods are synchronous). Then there is a separate "processor" which publishes these messages to a collector. If you insist on writing your own logging framework (why?), I would recommend you take the same approach as all the other highly successful logging frameworks.
I am using spring webflux to call one service from another via Schedulers.elastic()
Mono<Integer> anaNotificationCountObservable = wrapWithRetryForFlux(wrapWithTimeoutForFlux(
notificationServiceMediatorFlux.getANANotificationCountForUser(userId).subscribeOn(reactor.core.scheduler.Schedulers.elastic())
)).onErrorReturn(0);
In main thread i am setting one InhertitableThreadLocal variable and in the child thread I am trying to access it and it is working fine.
This is my class for storing threadlocal
#Component
public class RequestCorrelation {
public static final String CORRELATION_ID = "correlation-id";
private InheritableThreadLocal<String> id = new InheritableThreadLocal<>();
public String getId() {
return id.get();
}
public void setId(final String correlationId) {
id.set(correlationId);
}
public void removeCorrelationId() {
id.remove();
}
}
Now the issue is first time its working fine meaning the value i am setting in threadlocal is passed to other services.
But second time also, it is using old id(generated in last request).
I tried using Schedulers.newSingle() instead of elastic(), then its working fine.
So think since elastic() is re-using threads, thats why it is not able to clear / or it is re-using.
How should i resolve issue.
I am setting thread local in my filter and clearing the same in myfiler
requestCorrelation.setId(UUID.randomUUID().toString());
chain.doFilter(req,res)
requestCorrelation.removeCorrelationId();
You should never tie resources or information to a particular thread when leveraging a reactor pipeline. Reactor is itself scheduling agnostic; developers using your library can choose to schedule work on another scheduler - if you decide to force a scheduling model you might lose performance benefits.
Instead you can store data inside the reactor context. This is a map-like structure that’s tied to the subscriber and independent of the scheduling arrangement.
This is how projects like spring security and micrometer store information that usually belongs in a threadlocal.
I need to extract several header values at the start of each request and place them into a ClientContext object that can be injected into my application code by MEF. I am using Preview 5 of the WCF Web API and don't see a way to do this.
In 'standard' WCF, I would create a class that implements IExtension<OperationContext> and have the following property to wire it all together:
[Export(typeof(IClientContext)]
[PartCreationPolicy(CreationPolicy.NonShared)]
public static ClientContextExtension Current
{
get
{
var operationContext = OperationContext.Current;
if (operationContext == null)
return null;
var extension = operationContext.Extensions.Find<ClientContextExtension>();
if (extension == null)
{
extension = new ClientContextExtension();
operationContext.Extensions.Add(extension);
}
return extension;
}
}
A custom DelegatingHandler calls ClientContextExtension.Current and sets the properties from the header values. Unfortunately, with WCF Web API, OperationContext.Current is always null!
I cannot figure out a way to make this work with the Web API. Any help is appreciated!!!
I've come up with a working solution but remain open to other options. First, some rationale behind the original approach...
Because WCF uses thread pooling, anything based on a per-thread model may (and will) have a lifetime that extends beyond an individual request. I needed a way to store client context information pulled from the HTTP headers for each request as the information will be different each time. This means I can't persist the context information per-thread because the thread will be re-used.
Or can I?
The flaw in my logic was that thread re-use was the problem. In reality, each thread is only every servicing a single request at one time thereby making any information in that thread isolated to that request. Therefore, all I need to do is make sure that the information is relavent to that request and my problem is solved.
My solution was to refactor the Current property to reference a private static field marked with the [ThreadStatic()] attribute, ensuring that each instance was specific to the thread. Then, in my DelegatingHandler, which executes for each request, I reset the properties of the object for that request. Subsequent calls to Current during that request return the request-specific information and the next request handled by the thread gets updated in the DelegatingHandler so as far as my other code is concerned, the context is per-request.
Not perfect, but it at least gets me up and running for the moment. As I said, I am open to other solutions.
UPDATE
Upon closer inspection, this solution is not working as there is no thread affinity between the DelegatingHandler and the service code that is making use of the context object. As a result, sometimes my call to retrieve the ThreadStatic object works as expected but on other occasions I get a new instance because the code is operating on a different thread than the handler.
So, disregard this solution. Back to the drawing board.
UPDATE TO MY UPDATE
After discussing my problem with Glenn Block, it turns out that it is just a matter of making sure the context is set on the same thread the request handler (the service) is executing. The solution is to use an HttpOperationHandler instead of a MessageHandler.
According to Glenn, message handlers operate asynchronously which means they could execute on a different thread from the request handler (service) so we should never do anything in a message handler that requires thread affinity. On the other hand, operation handlers run synchronously on the same thread as the request handler, therefore we can rely on thread affinity.
So, I simply moved my code from a MessageHandler to an HttpOperationHandler and have the desired results.
You can read a full explanation here: http://sonofpirate.blogspot.com/2011/11/modeling-client-context-in-wcf-web-api.html
You can try to use a
HttpOperationHandler<HttpRequestMessage, HttpRequestMessage>
There you should be able to access the headers.
I have a Windows Service Application
in which i create WCF services in it.
One of the services is data
services: add, delete,
read , updatte data via
WCF.
WCF use NHibernate for data manipulation
So my guestions are:
Any advice (best practice) for session management for Hibernate using with WCF?
Anybody knows anything about
WcfOperationSessionContext (hibernate 3.0) class?
how to use it with WCF?
Well to make it concrete :
Suppose that i have WCF Service called DataServices
class WCFDataService .....
{
void SaveMyEntity(MyEntity entity)
{
.....................?? // How to do? Best Way
// Should i take one session and use it all times
// Should i take session and dipsose when operation finished then get
//new session for new operations?
// If many clients call my WCF service function at the same time?
// what may go wrong?
// etc....
}
}
And I need a NHibernateServiceProvider class
class NHibernateServiceProvider ....
{
// How to get Session ?? Best way
ISession GetCurrentSession(){.... }
DisposeSession(){ ....}
}
Best Wishes
PS: I have read similiar entries here and other web pages. But can not see "concrete" answers.
The WcfOperationSessionContext, similar to ThreadStaticSessionContext and WebRequestSessionContext is an implementation for a session context. The session context is used to bind (associate) a ISession instance to a particular context.
The session in the current context can be retrieved by calling ISessionFactory.GetCurrentSession().
You can find more information about session context here.
The WcfOperationSessionContext represents a context that spans for the entire duration of a WCF operation. You still need to handle the binding of the session in the begining of the operation and the unbinding/commiting/disposal of the session at the end of the operation.
To get access to the begin/end actions in the wcf pipeline you need to implement a IDispatchMessageInspector. You can see a sample here.
Also regarding WCF integration: if you use ThreadStatic session context it will appear to work on development, but you will hit the wall in production when various components (ex: authorization, authentication ) from the wcf pipeline are executed on different threads.
As for best practices you almost nailed it: Use WcfOperationSessionContext to store the current session and the IDispatchMessageInspector to begin/complete your unit of work.
EDIT - to address the details you added:
If you configured WcfOperationSessionContext and do the binding/unbinding as i explained above, all you have to do to is inject the ISessionFactory into your service and just use factory.GetCurrentSession(). I'll post a sample prj if time permits.
Here is the sample project
The model we use for managing NHibernate sessions with WCF is as follows:
1) We have our own ServiceHost class that inherits from System.ServiceModel.ServiceHost which also implements ICallContextInitializer. We add the service host instance to each of the operations in our service as follows:
protected override void InitializeRuntime()
{
base.InitializeRuntime();
foreach (ChannelDispatcher cd in this.ChannelDispatchers)
{
foreach (EndpointDispatcher ed in cd.Endpoints)
{
foreach (DispatchOperation op in ed.DispatchRuntime.Operations)
{
op.CallContextInitializers.Add(this);
}
}
}
}
public void AfterInvoke(object correlationState)
{
// We don't do anything after the invoke
}
public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message)
{
OperationContext.Current.Extensions.Add(new SessionOperationContext());
return null;
}
The BeforeInvoke simply makes sure that the OperationContext for each WCF call has it's own session. We have found problems with IDispatchMessageInspector where the session is not available during response serialisation - a problem if you use lazy loading.
2) Our SessionOperationContext will then be called to attach itself and we use the OperationCompleted event to remove ourselves. This way we can be sure the session will be available for response serialisation.
public class SessionOperationContext : IExtension<OperationContext>
{
public ISession Session { get; private set; }
public static SessionOperationContext Current
{
get
{
OperationContext oc = OperationContext.Current;
if (oc == null) throw new InvalidOperationException("Must be in an operation context.");
return oc.Extensions.Find<SessionOperationContext>();
}
}
public void Attach(OperationContext owner)
{
// Create the session and do anything else you required
this.Session = ... // Whatever instantiation method you use
// Hook into the OperationCompleted event which will be raised
// after the operation has completed and the response serialised.
owner.OperationCompleted += new EventHandler(OperationCompleted);
}
void OperationCompleted(object sender, EventArgs e)
{
// Tell WCF this extension is done
((OperationContext)sender).Extensions.Remove(this);
}
public void Detach(OperationContext owner)
{
// Close our session, do any cleanup, even auto commit
// transactions if required.
this.Session.Dispose();
this.Session = null;
}
}
We've used the above pattern successfully in high-load applications and it seems to work well.
In summary this is similar to what the new WcfOperationSessionContext does (it wasn't around when we figured out the pattern above;-)) but also overcomes issues surrounding lazy loading.
Regarding the additional questions asked: If you use the model outlined above you would simply do the following:
void SaveMyEntity(MyEntity entity)
{
SessionOperationContext.Current.Session.Save(entity);
}
You are guaranteed that the session is always there and that it will be disposed once the WCF operation is completed. You can use transactions if required in the normal way.
Here is a post describing, in detail, all the steps for registering and using the WcfOperationSessionContext. It also includes instructions for using it with the agatha-rrsl project.
Ok, after few days of reading internet posts etc. all approaches shown in the internets seems to be wrong. When we are using UnitOfWork pattern with NH 3^ with nhibernate transaction this all aprochaes are producing exceptions. To test it and proof that we need to create test enviroment with MSMQ transaction queue, special interface with OneWay operation contract with transaction required set on it. This approach should works like this:
1. We put transactionally message in queue.
2. Service is getting transactionally messege from queue.
3. Everything works queue is empty.
In some cases not so obious with internet approaches this does not work properly. So here are expamples which we tested that are wrong and why:
Fabio Maulo approach: Use ICallContextInitializer - open NH session/transaction on BeforeCall, after that WCF is executing service method, on AfterCall in context initializer we call session.Flush + transaction.commit. Automaticly session will be saved when transaction scope will commit operation. In situation when on calling transaction.Complete exception will be thrown WCF service will shutdown! Question can be ok, so take transaction.Complete in try/catch clausule - great! - NO wrong! Then transaction scope will commit transaction and message will be taken from queue but data will not be saved !
Another approach is to use IDispatchMessageInspector - yesterday I thought this is best approach. Here we need to open session/transaction in method AfterReceiveRequest, after WCF invoke service operation on message dispatcher inspector BeforeSendReply is called. In this method we have info about [reply] which in OneWay operation is null, but filled with fault information if it occured on invoking service method. Great I thought - this is this ! but NOT! Problem is that at this point in WCF processing pipe we have no transaction ! So if transaction.Complete throw error or session.Flush will throw it we will have not data saved in database and message will not come back to queue what is wrong.
What is the solution?
IOperationInvoker and only this!
You need to implement this interface as a decorator pattern on default invoker. In method Invoke before call we are openning session/transaction open then we call invoke default invoker and after that call transaction.complete in finally clausule we call session.flush. What types of problem this solves:
1. We have transaction scope on this level so when complete throws exception message will go back to queue and WCF will not shutdown.
2. When invocation will throw exception transaction.complete will not be called what will not change database state
I hope this will clear everyones missinformation.
In some free time I will try to write some example.