How can I get Multiple HashSet with ServiceStack Redis Client - redis

I want to get Multiple HashSet. There is
public HashSet<string> GetAllItemsFromSet (string setId){ ....}
I need
public HashSet<string>[] GetAllItemsFromSets (string[] setIds)
How?

The API doesn't exist on the RedisClient and there is no specific Redis server operation for this task so you have to add extend the Redis client yourself, which you can do easily with an Extension method, e.g:
public static class RedisClientExtensions {
public static HashSet<string>[] GetAllItemsFromSets(this IRedisClient client,
string[] setIds)
{
return setIds.Select(x => client.GetAllItemsFromSet(x)).ToArray();
}
}

Related

.NET 5 Web API: Storing data per request

When getting a request in any action of any controller, I look at the jwt know which user is requesting and lookup the user in the database to get some user-data that I want to use throughout the application. E.g. which departments the user belongs to or the users preferred language.
Now I could create a object which wraps these information and send it down the layers and pass it to every method that likes to use some of this data. But I like the data to be available to every method throughout the application without passing it in every method. Like e.g. dependency injection (Seems to late at that point) or something else I can get access to that data quickly.
Any advice of how to handle it?
Try it with the Items property on the HttpContext. By using it you can store data during a single request. The only downside with this approach is that every service needs to have access to the HttpContext to read the values. Values can be added to the Items Dictionary as shown below
public class IndexModel : PageModel
{
//
public void OnGet()
{
HttpContext.Items.Add("Key", new RequestInfo { Key = "RequestKey" });
}
}
class RequestInfo
{
public string Key { get; set; }
}
You can then access the value by registering the IHttpContextAccessor to the IServiceCollection and then using Constructor injection to use the HttpContext in your service so that you can work with the Items Dictionary.
public class Service
{
private IHttpContextAccessor _htp;
public Service(IHttpContextAccessor http)
{
_htp = http;
}
public void Log()
{
Console.WriteLine(((RequestInfo)_htp.HttpContext.Items["Key"]).Key);
}
}

StackExchange.Redis: How to configure Redis instance

I have a Redis instance and I want StackExchange.Redis to connect to that specific instance, but I am unable to find any configuration to set the InstanceName!
You can have an extension method like this:
public static IServiceCollection AddRedisQueue(this IServiceCollection services, IConfiguration configuration)
{
var options = configuration.GetOptions<RedisOptions>(SectionName);
var multiplexer = ConnectionMultiplexer.Connect(options.ConnectionString);
services.AddSingleton<IConnectionMultiplexer>(multiplexer);
return services;
}
Where RedisOptions is a class like this and section name is redis config name in your settings file:
public class RedisOptions
{
public string ConnectionString { get; set; }
public string Instance { get; set; }
}
Then you can inject it in Startup.cs ConfigureServices method like this:
services.AddRedisQueue(Configuration);
Later in code you just inject IConnectionMultiplexer from the constructor of the class where you would like to use redis, and get database by calling IConnectionMultiplexer's GetDatabase() method. About Instance property of redis options, you use it when providing a key:
var key = $"{redisOptions.Value.Instance}some_key";
Then use this key when dealing with IDatabase instance of stack exchange.

Multiple IDistributedCache definitions are not closing redis connections

I have the following solution in order to implement multiple IDistributedCache definitions:
public interface IDBCache : IDistributedCache
{
}
public class DBCacheOptions : RedisCacheOptions { }
public class DBCache : RedisCache, IDBCache
{
public DBCache(IOptions<DBCacheOptions> optionsAccessor) : base(optionsAccessor)
{
}
}
And I have other definitions like the above pointint to different redis instances.
I am registering the cache service at Startup.cs as:
services.Configure<DBCacheOptions>(options => options.Configuration = configuration.GetValue<string>("Cache:DB"));
services.Add(ServiceDescriptor.Singleton<IDBCache, DBCache>());
And then I am wrapping IDBCache as:
public class DBCacheManager
{
private const string DB_CACHE_FORMAT = "DB:{0}";
private const int DB_EXPIRATION_HOURS = 8;
private readonly IDistributedCache _cache;
public DBCacheManager(IDBCache cache)
{
_cache = cache;
}
public Task AddDBItem(string name, string value)
{
return _cache.SetStringAsync(string.Format(DB_CACHE_FORMAT, name), value,
new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(DB_EXPIRATION_HOURS) });
}
}
And when I check for clients connected to redis (info clients command) connected_clients are incrementing without stopping, also when I see the clients list (client list command) I see the large connection list with long ages and idles.
Insights: I am using redis implementation of AWS ElasticCache which has unlimited idle timeout by default but I guess I should not be forcing to close these connections, should I? I suppose my application should be responsible.
This was a bad implementation of dependency injection. IDistributedCache interface does not have implementation of redis INCR command so somewhere in our project we were connecting directly using StackExchange.Redis with a DI wrapper that was creating multiple connection multiplexers and IDatabases.
Bottom line: my bad

Transition from Entityspaces(Tiraggo) into Servicestack Ormlite

at this moment we are migrating from Entityspaces(Tiraggo) into Servicestack Ormlite.
One point is the way to open and close the DBConnection.
I apologize for the comparission but it is useful for the question. In Tiraggo, inside my wep application, in the global.asax.cs I put this:
protected void Application_Start(object sender, EventArgs e)
{
Tiraggo.Interfaces.tgProviderFactory.Factory = new Tiraggo.Loader.tgDataProviderFactory();
}
In web.config exists the section for Tiraggo, the connectionstring and the ORM does the rest.
During the use of the classes we just do this:
User user = new User(); user.Name="some"; user.Comment = "some"; user.Save();
I dont open, close a DBConnection. It is transparent for the programmer. Just create the instance classes and use them.
I define a class, a repository and that's all. No DB definition or interaction. Everything happens in a webforms app, with the datalayer inside the same app.
When we are migrating to Servicestack ORMLite, I see the open of the DBConnection is too inside the globlal.asax.cs, but it references a Service no a class or repository.
public class AppHost : AppHostBase
{
public AppHost() : base("Hello ServiceStack", typeof(HelloService).Assembly) {}
public override void Configure(Container container) {}
}
So my first question is: how can I use it if I dont have a Service (HelloService), I have just classes or repositories. So I cant use this technique for DBConnection my DB.
I also see that accesing the Db, I need a open connection. I try to do this:
using (var Db = DbFactory.Conn.OpenDbConnection())
{
return Db.SingleById<Anio>(id);
}
Later, I found a sample like I was looking for, the Pluralsight video ".NET Micro ORMs" Steve Mihcelotti, and he just open the connection, but never Close it, never use the "using" syntax.
So my 2 questions are:
1) Is there a way for open the DbFactory(dbConnection) like all the samples using servicestack ormlite, but without using a Services ( I dont use Services, I want to use Ormlite but just with classes and repositories)
2) Is there a way for connnect to the database in each trip to the class or repository without using the "using" syntax, or
3) the only way is the one showed in the Pluralsight video, ie. open the connection throw the using syntax in each Method (trip to the class)
I hope I was clear.
The nice thing about IDbConnectionFactory is that it's a ThreadSafe Singleton which can be safely passed around and referenced as it doesn't hold any resources open itself (i.e. DB Connections).
A lazy pattern which provides a nice call-site API is the RepositoryBase class:
public abstract class RepositoryBase : IDisposable, IRepository
{
public virtual IDbConnectionFactory DbFactory { get; set; }
IDbConnection db;
public virtual IDbConnection Db
{
get { return db ?? (db = DbFactory.OpenDbConnection()); }
}
public virtual void Dispose()
{
if (db != null)
db.Dispose();
}
}
This is the same pattern ServiceStack's Service class uses to provide a nice API that only gets opened when it's used in Services, e.g:
public class MyRepository : RepositoryBase
{
public Foo GetFooById(int id)
{
return Db.SingleById<Foo>(id);
}
}
Note: This pattern does expect that your dependencies will be disposed after use.
Another alternative is to leverage your IOC to inject an Open IDbConnection with a managed lifetime scope, e.g:
container.Register<IDbConnection>(c =>
c.Resolve<IDbConnectionFactory>().OpenDbConnection())
.ReusedWithin(ReuseScope.Request);
The life-cycle of the connection is then up to your preferred IOC.
Without Using an IOC
Whilst it's typically good practice to use an IOC to manage your Apps dependencies and provide loose-coupling, if you don't want to use an IOC you can also make DbFactory a static property, e.g:
public abstract class RepositoryBase : IDisposable
{
public static IDbConnectionFactory DbFactory { get; set; }
IDbConnection db;
public virtual IDbConnection Db
{
get { return db ?? (db = DbFactory.OpenDbConnection()); }
}
public virtual void Dispose()
{
if (db != null)
db.Dispose();
}
}
Which you can just initialize directly on startup, e.g:
protected void Application_Start(object sender, EventArgs e)
{
RepositoryBase.DbFactory = new OrmLiteConnectionFactory(
connectionString, SqlServer.Provider);
}
Note: If you're not using an IOC then you want to make sure that instances of your repository classes (e.g. MyRepository) are disposed of after use.

Where to store data for current WCF call? Is ThreadStatic safe?

While my service executes, many classes will need to access User.Current (that is my own User class). Can I safely store _currentUser in a [ThreadStatic] variable? Does WCF reuse its threads? If that is the case, when will it clean-up the ThreadStatic data? If using ThreadStatic is not safe, where should I put that data? Is there a place inside OperationContext.Current where I can store that kind of data?
Edit 12/14/2009: I can assert that using a ThreadStatic variable is not safe. WCF threads are in a thread pool and the ThreadStatic variable are never reinitialized.
There's a blog post which suggests implementing an IExtension<T>. You may also take a look at this discussion.
Here's a suggested implementation:
public class WcfOperationContext : IExtension<OperationContext>
{
private readonly IDictionary<string, object> items;
private WcfOperationContext()
{
items = new Dictionary<string, object>();
}
public IDictionary<string, object> Items
{
get { return items; }
}
public static WcfOperationContext Current
{
get
{
WcfOperationContext context = OperationContext.Current.Extensions.Find<WcfOperationContext>();
if (context == null)
{
context = new WcfOperationContext();
OperationContext.Current.Extensions.Add(context);
}
return context;
}
}
public void Attach(OperationContext owner) { }
public void Detach(OperationContext owner) { }
}
Which you could use like that:
WcfOperationContext.Current.Items["user"] = _currentUser;
var user = WcfOperationContext.Current.Items["user"] as MyUser;
An alternative solution without adding extra drived class.
OperationContext operationContext = OperationContext.Current;
operationContext.IncomingMessageProperties.Add("SessionKey", "ABCDEFG");
To get the value
var ccc = aaa.IncomingMessageProperties["SessionKey"];
That's it
I found that we miss the data or current context when we make async call with multiple thread switching. To handle such scenario you can try to use CallContext. It's supposed to be used in .NET remoting but it should also work in such scenario.
Set the data in the CallContext:
DataObject data = new DataObject() { RequestId = "1234" };
CallContext.SetData("DataSet", data);
Retrieving shared data from the CallContext:
var data = CallContext.GetData("DataSet") as DataObject;
// Shared data object has to implement ILogicalThreadAffinative
public class DataObject : ILogicalThreadAffinative
{
public string Message { get; set; }
public string Status { get; set; }
}
Why ILogicalThreadAffinative ?
When a remote method call is made to an object in another AppDomain,the current CallContext class generates a LogicalCallContext that travels along with the call to the remote location.
Only objects that expose the ILogicalThreadAffinative interface and are stored in the CallContext are propagated outside the AppDomain.