Re-using reference to an IReliableCollection - azure-service-fabric

Is it acceptable to re-use a reference to a IReliableCollection or should I request from IReliableStateManager every time I want to use it?
For example, if I have a dictionary that is widely used in my application, is it acceptable to retrieve it once in the RunAsync method and then pass this reference to any method that requires it, e.g:
protected override async Task RunAsync(CancellationToken cancellationToken)
{
_someCollection = StateManager.GetOrAddAsync<IReliableDictionary<int, string>>(
"SomeName");
}
public async Task DoSomething(int id, string message)
{
_someClass.DoSomething(_someCollection, id, message);
}
And then use in a class like so:
public class SomeClass
{
public void DoSomething(IReliableDictionary<int, string> dict, int id, string msg)
{
using (ITransaction tx = StateManager.CreateTransaction())
{
await dict.AddAsync(tx, id, msg);
await tx.CommitAsync();
}
}
}
Or should I request from IReliableStateManager on each call, e.g,
public class SomeClass
{
public void DoSomething(int id, string msg)
{
var dict = StateManager.GetOrAddAsync<IReliableDictionary<int, string>>("SomeName");
using (ITransaction tx = StateManager.CreateTransaction())
{
await dict.AddAsync(tx, id, msg);
await tx.CommitAsync();
}
}
}
Passing a reference seems to work fine from what I can tell but I'm not sure whether this would be considered bad practice and I can't find a definitive answer in the guidelines or documentation

Yes. You can.
You can check this to see how you can even receive notifications when new instance of IReliableState is added to ReliableStateManager.
You can also subscribe for events (if this is a dictionary).

Related

Delete multiple row with ids without foreach and postman test

I have a little problem. But I dont know why it doesnt work. And I dont know how to post all ids by postman.
I am using unit of work with generic repository. I want to send int[] ids to my controller. I dont want to send entity. I searched a lot it today. And I changed my code. But what is problem now?
This is my repostiroy:
public async Task DeleteRangeAsync(Expression<Func<T, bool>> predicate)
{
IQueryable<T> query = _dbSet.Where(predicate);
await Task.Run(() => { _dbSet.RemoveRange(query.AsNoTracking()); });
}
This is my KulturManager:
public async Task<IResult> HardDeleteRangeAsync(int[] ids)
{
await UnitOfWork.Kulturs.DeleteRangeAsync(c => ids.Contains(c.Id));
await UnitOfWork.SaveAsync();
return new Result(ResultStatus.Success, Messages.Info("Kultur", "HardDelete"));
}
And this is my KulturController:
[HttpDelete("{ids}")]
public async Task<IActionResult> HardDeleteRangeAsync(int[] ids)
{
var result = await _kulturManager.HardDeleteRangeAsync(ids);
return Ok(result.Message);
}
Thank you for help
You shouldn't fetch all the entities you want to delete. Instead create stub entities for RemoveRange. If you don't have a common base class, this requires reflection, but with a common entity base class you can do it like this:
public void DeleteRange<T>(int[] ids) where T: BaseEntity, new()
{
_dbSet.RemoveRange(ids.Select(i => new T() { Id = i }).ToList());
}
or if the method is in a generic class, the method would look like
public void DeleteRange(int[] ids)
{
_dbSet.RemoveRange(ids.Select(i => new T() { Id = i }).ToList());
}
And there's no reason to mark this as Async now since it doesn't do any database access.

Returning a value from Task<IActionResult>

I have this OnGet method that runs in a razorpage when I click the approve button.
As you can see below the actual code that runs is in a utility class and as I do not want to break the threading procedure the utility class method also returns the Task
When the execution returns I write the "message" to the browser. My problem is that it is not the Id I want to display for the user. it is another column in sql which is available in the utility class.
So my question here is how can change my call to return a value from the Utility class method?
public async Task<IActionResult> OnGetApproveAsync(int id) {
try {
await Utils.ApproveOrder(Request, HttpContext, _context1, _context2, _cache, id);
Message += "Order #" + id + " Approved\n";
return Redirect("~/Orders/Orders");
} catch (Exception e) {
Message += e.StackTrace.ToString();
return Redirect("~/Orders/Orders");
}
}
Change Utils.ApproveOrder to return Task<Utility> and update model code
public async Task<IActionResult> OnGetApproveAsync(int id) {
try {
Utility util = await Utils.ApproveOrder(Request, HttpContext, _context1, _context2, _cache, id);
//use util
//..
}

need information in a BayeuxServer.Session Listener

I would like to keep information about my logged in users available in my webapp; so, for example, I pass an identifier to SessionListener.sessionAdded in the ServerMessage, and use the identifier to load user info into a persistent hash.
Likewise, when a session is destroyed, I would like to erase the client information from the hash when SessionListener.sessionRemoved is called. However, there is no message. Can I use ServerSession.getUserAgent(), and what is the String that it returns?
Or, is there one SessionListener per session, so that I can save the email locally in the SessionListener for use when sessionRemoved is called?
You have 2 choices.
With a session attribute:
class MySessionListener implements BayeuxServer.SessionListener {
public void sessionAdded(ServerSession session, ServerMessage message) {
session.setAttribute("token", message.getDataAsMap().get("token"));
}
public void sessionRemoved(ServerSession session, boolean timedout) {
String token = (String)session.getAttribute("token");
// Use the token here.
}
}
Or with a RemoveListener:
class MySessionListener implements BayeuxServer.SessionListener {
public void sessionAdded(ServerSession session, ServerMessage message) {
final String token = (String)message.getDataAsMap().get("token");
session.addListener(new RemoveListener() {
public void removed(ServerSession session, boolean timeout) {
// Use token here.
}
});
}
public void sessionRemoved(ServerSession session, boolean timedout) {
// Nothing to do here.
}
}

How to wrap HttpClient for testability in C#

I'm calling an external API and would like my API to be unit testable. And to do that, i'm trying to wrap HttpClient. I only need one method for now.
Here is my interface.
public interface IHttpClient
{
Task<string> GetStringAsync(string url);
}
And this is how I implemented it.
public class HttpClientWrapper : IHttpClient
{
private readonly HttpClient _httpClient;
public HttpClientWrapper()
{
// I could also inject this but I think this will be fine as is.
_httpClient = new HttpClient(new HttpClientHandler(), false);
}
public async Task<string> GetStringAsync(string url)
{
//validate url here
return await _httpClient.GetStringAsync(url);
}
}
Doubts I have? is this the right way to do it? Will setting the bool parameter result in resource leaking here? I read a couple of conflicting ideas about whether HttpClient has to be disposed on every call or not. I took, the not disposing side but am not really quite certain though.
If there is a way to use HttpClient without having a wrapper but make the API testable, that will be great too. But so far, i failed to get that working.
Thanks,
CleanKoder
While it could still be nice to create an interface for the client, the HttpClient class is actually designed with testability in mind! When instantiating your HttpClient you can inject a custom HttpMessageHandler. By overriding Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) in this class, you can interrupt all requests before they are actually written to the socket, inspecting them and returning whatever you see fit.
Here is an example of such a test double I wrote in a project, feel free to modify it to suit your needs:
public class FakeHttpMessageHandler : HttpMessageHandler
{
public HttpRequestMessage LastRequest;
public string LastRequestString = string.Empty;
public string ResponseContent = string.Empty;
public HttpStatusCode ResponseStatusCode = HttpStatusCode.OK;
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
if (request.Content != null)
{
LastRequestString = await request.Content.ReadAsStringAsync();
}
LastRequest = request;
return await Task.FromResult(new HttpResponseMessage
{
StatusCode = ResponseStatusCode,
Content = new StringContent(ResponseContent)
});
}
}
You could also use some isolation framework like NSubstitute if you think that's more appropriate for your project.

How to resend a GWT RequestFactory request

Is it possible to resend a RequestFactory transmission? I'd like to do the equivalent of this: How to resend a GWT RPC request when using RequestFactory. It is fairly simple to resend the same payload from a previous request, but I also need to place a call to the same method. Here's my RequestTransport class, and I am hoping to just "refire" the original request after taking care of, in this case, a request to the user for login credentials:
package org.greatlogic.rfexample2.client;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.Response;
import com.google.web.bindery.requestfactory.gwt.client.DefaultRequestTransport;
/**
* Every request factory transmission will pass through the single instance of this class. This can
* be used to ensure that when a response is received any global conditions (e.g., the user is no
* longer logged in) can be handled in a consistent manner.
*/
public class RFERequestTransport extends DefaultRequestTransport {
//--------------------------------------------------------------------------------------------------
private IClientFactory _clientFactory;
//==================================================================================================
private final class RFERequestCallback implements RequestCallback {
private RequestCallback _requestCallback;
private RFERequestCallback(final RequestCallback requestCallback) {
_requestCallback = requestCallback;
} // RFERequestCallback()
#Override
public void onError(final Request request, final Throwable exception) {
_requestCallback.onError(request, exception);
} // onError()
#Override
public void onResponseReceived(final Request request, final Response response) {
if (response.getStatusCode() == Response.SC_UNAUTHORIZED) {
_clientFactory.login();
}
else {
_clientFactory.setLastPayload(null);
_clientFactory.setLastReceiver(null);
_requestCallback.onResponseReceived(request, response);
}
} // onResponseReceived()
} // class RFERequestCallback
//==================================================================================================
#Override
protected void configureRequestBuilder(final RequestBuilder builder) {
super.configureRequestBuilder(builder);
} // configureRequestBuilder()
//--------------------------------------------------------------------------------------------------
#Override
protected RequestCallback createRequestCallback(final TransportReceiver receiver) {
return new RFERequestCallback(super.createRequestCallback(receiver));
} // createRequestCallback()
//--------------------------------------------------------------------------------------------------
void initialize(final IClientFactory clientFactory) {
_clientFactory = clientFactory;
} // initialize()
//--------------------------------------------------------------------------------------------------
#Override
public void send(final String payload, final TransportReceiver receiver) {
String actualPayload = _clientFactory.getLastPayload();
TransportReceiver actualReceiver;
if (actualPayload == null) {
actualPayload = payload;
actualReceiver = receiver;
_clientFactory.setLastPayload(payload);
_clientFactory.setLastReceiver(receiver);
}
else {
actualReceiver = _clientFactory.getLastReceiver();
}
super.send(actualPayload, actualReceiver);
} // send()
//--------------------------------------------------------------------------------------------------
}
Based upon Thomas' suggestion I tried sending another request, and just replaced the payload and receiver in the RequestTransport.send() method, and this worked; I guess there is no further context retained by request factory, and that the response from the server is sufficient for RF to determine what needs to be done to unpack the response beyond the request and response that are returned to the RequestCallback.onResponseReceived() method. If anyone is interested in seeing my code then just let me know and I'll post it here.
It's possible, but you have a lot to do.
I had the same idea. And i was searching for a good solution for about 2 days. I tried to intercept the server call on RequestContext.java and on other classes. But if you do that you have to make your own implementation for nearly every class of gwt requestfactories. So i decided to go a much simpler approach.
Everywhere where I fired a Request, i handled the response and fired it again.
Of course you have to take care, that you don't get in to a loop.