IDistributedCache on web API Get Method - caching

I need some help how can I do caching below on an async call. The cache is injected, i just need to implement it inside the Task call...
public SvcBooking(
DbContextSMATA ctx,
IMapper mapper,
IDistributedCache cache)
{
_ctx = ctx;
_mapper = mapper;
_Bookings = ctx.Set<Booking>();
_cache = cache;
}
#endregion
#region Public Methods
public async Task<IList<IDtoBooking>> GetAll()
{
// _cache.GetAsync() not sure how to do this
IList<Booking> settings = await _Bookings.ToListAsync();
return _mapper.Map<IList<IDtoBooking>>(settings);
}

Found a way to do this.. Yipee!!
public async Task<IList<Booking>> GetAll()
{
//First assign a KEY (anything that you think of that makes
// sense to the application and Unique)
IList<Booking> bookings;
byte[] bookingsInBytes= await _cache.GetAsync($"bookingsSampleKey");
if (bookingsSampleKey== null)
{
bookings= await _Bookings.ToListAsync();
//Now we are caching here, the data is saved into cache so that when a
//concurrent user tries to RE-query it within 60 seconds
//, it would go to the ELSE below
bookings= await _svcBooking.GetAll();
string bookingsSerialized= JsonConvert.SerializeObject(bookings);
bookingsInBytes= Encoding.UTF8.GetBytes(bookingsSerialized);
await _cache.SetAsync($"bookingsSampleKey", bookingsInBytes,
new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow =
TimeSpan.FromSeconds(60) });
}
else
{
//if I see some DATA already cached, I will retrieve it and return it
//instead of hitting the inner service
bookings= JsonConvert.DeserializeObject<IList<Booking>>(Encoding.UTF8.GetString(bookingsInBytes));
}
return bookings;
}

Related

Return object from async method into CompletableFuture<Object> list?

I have a list of objects (from model class Name) that I want to process using an async method. The async method will take each Name object in the list and process it (check if it's not taken), I want to have a list of Names after they all get processed by the async method to get returned to the isNameAvailable(LinkedHashSet<Name> nameList) method
My executor config
#Configuration
#ManagedResource
public class ThreadConfig {
#Bean(name = "nameAvailabilityExecutor")
public Executor nameAvailabilityExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(100);
executor.setMaxPoolSize(1200);
executor.setQueueCapacity(10000);
executor.setThreadNamePrefix("nameAvailabilityExecutor-");
executor.initialize();
return executor;
}
}
Service class which will call the Async method in another class
public LinkedHashSet<Name> isNameAvailable(LinkedHashSet<Name> nameList) {
LinkedHashSet<Name> nameCheckedList = new LinkedHashSet<>();
for (Name nameObj : nameList) {
Name nameCheckedObj = domainAvailabilityServiceThread.isNameAvailable(nameObj);
nameCheckedList.add(nameCheckedObj);
}
return nameCheckedList;
}
The async method which will do the processing
#Async("nameAvailabilityExecutor")
public Name isNameAvailable(Name nameObj) {
String name = nameObj.getName();
if (getByNameCheck(name)) {
nameObj.setAvailable(true);
} else {
nameObj.setAvailable(false);
}
return nameObj;
}
From my understanding CompletableFuture is what I need to use here? What is the correct way using CompletableFuture in this scenario?
You can simply make isNameAvailable(Name) return a CompletableFuture:
#Async("nameAvailabilityExecutor")
public CompletableFuture<Name> isNameAvailable(Name nameObj) {
String name = nameObj.getName();
if (getByNameCheck(name)) {
nameObj.setAvailable(true);
} else {
nameObj.setAvailable(false);
}
return CompletableFuture.completedFuture(nameObj);
}
Spring #Async will deal with the asynchronous execution as you intended.
You will also need to change the return type of isNameAvailable(LinkedHashSet) to a simple List or something similar, since it does not really make sense to store CompletableFutures in a Set:
public List<CompletableFuture<Name>> isNameAvailable(LinkedHashSet<Name> nameList) {
List<CompletableFuture<Name>> nameCheckedList = new ArrayList<>();
for (Name nameObj : nameList) {
CompletableFuture<Name> nameCheckedObj = domainAvailabilityServiceThread.isNameAvailable(nameObj);
nameCheckedList.add(nameCheckedObj);
}
return nameCheckedList;
}
Note that it is probably not a good idea to asynchronously modify the state of an object like you are doing here with Name, as it makes it more difficult to guarantee what state will be visible to the calling thread. It might be preferable to work with CompletableFuture<Boolean>:
#Async("nameAvailabilityExecutor")
public CompletableFuture<Boolean> isNameAvailable(Name nameObj) {
String name = nameObj.getName();
return CompletableFuture.completedFuture(getByNameCheck(name));
}
and return a Map<Name, CompletableFuture<Boolean>>:
public Map<Name, CompletableFuture<Boolean>> isNameAvailable(LinkedHashSet<Name> nameList) {
Map<Name, CompletableFuture<Boolean>> nameCheckedList = new HashMap<>();
for (Name nameObj : nameList) {
CompletableFuture<Boolean>> nameCheckedObj = domainAvailabilityServiceThread.isNameAvailable(nameObj);
nameCheckedList.put(nameObj, nameCheckedObj);
}
return nameCheckedList;
}
and let the calling thread do whatever is needed with that check.

Store Workflow Activity Data When Publishing

I Need to store a specific activity data in another collection in database whenever a user publish a workflow in elsa.
I dont find any documentation, Please suggest me some resource or suggestion to achieve this. I have try to implement this with middleware. The Middleware code is
namespace WorkFlowV3
{
// You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project
public class CustomMiddleware
{
private readonly RequestDelegate _next;
static HttpClient client = new HttpClient();
public CustomMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
//Write Custom Logic Here....
client.BaseAddress = new Uri("#");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
string path = "/api/test-middleware-call";
HttpResponseMessage response = await client.GetAsync(path);
await _next(httpContext);
}
}
// Extension method used to add the middleware to the HTTP request pipeline.
public static class CustomMiddlewareExtensions
{
public static IApplicationBuilder UseCustomMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<CustomMiddleware>();
}
}
}
But in this process, I cant fetch the specific activity data.
The easiest way to store information in your own DB in response to the "workflow published" event is by implementing a notification handler (from MediatR) that handles the WorkflowDefinitionPublished notification.
For example:
public class MyWorkflowPublishedhandler : INotificationhandler<WorkflowDefinitionPublished>
{
private readonly IMyDatabaseStore _someRepository;
public MyWorkflowPublishedhandler(IMyDatabaseStore someRepository)
{
_someRepository = someRepository;
}
public async Task Handle(WorkflowDefinitionPublished notification, CancellationToken cancellationToken)
{
var workflowDefinition = notification.WorkflowDefinition;
// Your logic to do a thing.
}
}
To register this handler, from your Startup or Program class, add the following code:
services.AddNotificationHandler<MyWorkflowPublishedhandler>();
Your handler will be invoked every time a workflow gets published.

How to implement HttpClient in Xamarin.Forms applications using better CPU and Memory?

I am bit confused about all those problems and workarounds of httpclient usage in xamarin.forms. I would like to summarize my understanding and hesitations/questions
Disposing every time vs Singleton HttpClient and Static Client: It is said that dont use using around httpClient and use singleton implementation as stated in this article
Wrong;
var httpClient = new HttpClient(new HttpClientHandler
{
//Some settings
});
Correct:
public class HttpService
{
private readonly HttpClient _httpClient;
public HttpService()
{
_httpClient = CreateHttpClient();
}
Here the first question, if we dont use static what is the advantage of this?
Because HttpService will start a new client for each thread, not? If we use static client, will this cause any memory cycle?
Xamarin forms is very fragile about static dependency, if you are holding a static value inside a ViewModel and ViewModel is coupled with View using Freshmvvm, Prism etc., usually View wont be disposed and instance remains in the memory and causes memory leak even after popping the page.
DNS changes problem: it looks like that there is a problem to use singleton HttpClient whenever DNs changes as described here. How to overcome this problem in a xamarin.forms application? I dont see any ServicePointManager defined in .net standard 2.0. Do I really have to worry about this?
ReadAsStreamAsync vs ReadAsStringAsync when getting response. Does it make a big difference to use ReadAsStreamAsync? and is there any side effect to use as stream?
Should we dispose HttpResponseMessage with a using like below?
using (HttpResponseMessage response = await client.GetAsync(uri))
{
if (!response.IsSuccessStatusCode)
{
//Do something
}
else
{
//Do something
}
}
Finally my Class looks like as below; Do you see any problem with this?
proxy setting are described in this article
namespace myApp
{
public class HttpService
{
private readonly HttpClient client;
private JsonSerializer _serializer = new JsonSerializer();
public HttpService()
{
if (client == null)
{
try
{
HttpClientHandler handler = new HttpClientHandler
{
Proxy = Xamarin.Forms.DependencyService.Get<IProxyInfoProvider>().GetProxySettings()
};
client = new HttpClient(handler);
}
catch (Exception ex)
{
}
}
}
public async Task<T> GetItemAsync<T>(string url, CancellationToken cancellationToken=default(CancellationToken))
{
T returnObject = default(T);
Uri uri = new Uri(url);
try
{
using (HttpResponseMessage response = await client.GetAsync(uri,cancellationToken))
{
if (!response.IsSuccessStatusCode)
{
//Handle error
}
else
{
returnObject = await getReturnObject<T>(response);
}
}
}
catch (OperationCanceledException)
{
}
catch (System.Net.Http.HttpRequestException)
{
}
catch (Exception ex)
{
}
return returnObject;
}
public async Task<T> getReturnObject<T>(HttpResponseMessage response)
{
T returnObject = default(T);
if (response.IsSuccessStatusCode)
{
using (System.IO.Stream stream = await response.Content.ReadAsStreamAsync())
using (System.IO.StreamReader reader = new System.IO.StreamReader(stream))
using (JsonTextReader json = new JsonTextReader(reader))
{
returnObject = _serializer.Deserialize<T>(json);
}
//string content = await response.Content.ReadAsStringAsync();
//returnObject = JsonConvert.DeserializeObject<T>(content);
}
return returnObject;
}
}
}

running wf workflow from mvc controller

enter code hereI intend to use WF4.5 in a web application which is written by MVC Framework. I have used WorkflowApplication class instance to run my WorkFlow with. but whenever i call the method in controller that run the instance I get this error:
An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%# Page Async="true" %>. This exception may also indicate an attempt to call an "async void" method, which is generally unsupported within ASP.NET request processing. Instead, the asynchronous method should return a Task, and the caller should await it
I have written this class which is resposnsible to execute workflow:
public class WorkFlowsPipeline : IWorkFlowsPipeline
{
private IUnitOfWork _unitOfWork;
private SqlWorkflowInstanceStore _instanceStore;
public WorkFlowsPipeline(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
//workflowInstanceStore
_instanceStore = new SqlWorkflowInstanceStore();
_instanceStore.ConnectionString ="data source=.;initial catalog=WFPersist;user id=sa;password=1;";
}
public void RecordPersistedInstanceForTheUser(int userId,Guid instanceId, Models.Enums.WorkFlowTypeEnum workFlowType)
{
_unitOfWork.UsersWorkFlows.Add(new UsersWorkFlowsInstance
{
UserId = userId,
WorkFlowId=instanceId,
WorkFlowType = workFlowType
});
}
public void RunCompleteProfileForUser(int userId)
{
var usersWorkFlow = _unitOfWork.UsersWorkFlows.GetAll().FirstOrDefault(x => x.UserId == userId);
if (usersWorkFlow == null)
{
Activity rentalWorkflow = new Activity1();
Dictionary<string, object> wfArg = new Dictionary<string, object>()
{
{
"UOW", _unitOfWork
},
{
"UserId",userId
}
};
var _wfApp = new WorkflowApplication(rentalWorkflow, wfArg);
_wfApp.SynchronizationContext = SynchronizationContext.Current;
_wfApp.InstanceStore = _instanceStore;
//_wfApp.Extensions.Add(this);
var instanceId=_wfApp.Id;
_wfApp.Run();
RecordPersistedInstanceForTheUser(userId, instanceId,WorkFlowTypeEnum.CompleteProfile);
}
else
{
//get id of instance load it from database and run it
}
}
}
and I called the method in my controller action in this way:
public async Task<ActionResult> Index()
{
var userId = User.Identity.GetUserId<int>();
_workFlowsPipeline.RunCompleteProfileForUser(userId);
return View();
}
Use WorkflowInvoker instead of WorkflowApplication.

Logging response and request to OAuth provider

Is there a way to capture the response from requests served by OAuth? Specifically, I need to log the request and response from OAuthAuthorizationServerProvider.GrantResourceOwnerCredentials().
I've tried extending OwinMiddleware and overriding Invoke as shown in this post, but I'm unable to read the response body. I'd like to use a message handler as this post demonstrates, but I don't have UseHttpMessageHandler on my AppBuilder object.
Any help would be greatly appreciated.
Thank you!
Update
Modifying the example provided in Brock's excellent video, here's what I need to do:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Use(typeof(MW1));
app.Map("/api", fooApp => {
fooApp.Use<MW2>();
});
}
}
public class MW1 {
Func<IDictionary<string, object>, Task> next;
public MW1(Func<IDictionary<string, object>, Task> next) {
this.next = next;
}
public async Task Invoke(IDictionary<string, object> env) {
var ctx = new OwinContext(env);
await next(env);
// I need to be able to read: <h1>MW2 called</h1> written by MW2
var body = ctx.Response.Body;
// body.CanRead = False
}
}
public class MW2 {
Func<IDictionary<string, object>, Task> next;
public MW2(Func<IDictionary<string, object>, Task> next) {
this.next = next;
}
public async Task Invoke(IDictionary<string, object> env) {
var ctx = new OwinContext(env);
await ctx.Response.WriteAsync("<h1>MW2 called</h1>");
await next(env);
}
}
I actually need to read the response sent from the OAuth provider, but I assume it would be the same process.
Why not implement an OWIN middleware component that sits in front of the OAuth AS middleware?

Resources