We are trying to connect to Azure Cache for Redis using C# code. Its returns NULL object.
This started happing after we converting our public subnet to private subnet.
private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() =>
{
var redisConnectionString = ConfigurationManager.ConnectionStrings["RedisCacheCnStr"].ConnectionString;
return ConnectionMultiplexer.Connect(redisConnectionString);
});
public static ConnectionMultiplexer Connection { get { return lazyConnection.Value; } }
We checked logs we are getting object reference error as connected object is Null.
Check the below steps to connect Azure Cache for Redis in Private Subnet.
First create a Virtual Network.
Create a Subnet with the Virtual Network.
Initially you will have a default subnet. Create one more with your NSG.
Make sure you have selected the NSG.
Create Azure Cache for Redis
There is no change in the code which you are trying to connect.
string cacheConnection = ConfigurationManager.ConnectionStrings["CacheConnection"].ConnectionString;
connection = ConnectionMultiplexer.Connect(cacheConnection);
Just update the connection string with the IP address.
In web.config,add the connection string.
<connectionStrings>
<add name="CacheConnection" connectionString="IPAddress:PortNo,password=redis-cache-key,abortConnect=False" />
</connectionStrings>
Get the IPAddress from Virtual Network in Azure Cache for Redis.
Related
I tried to connect cassandra from virtual machine to main machine and use it with CassandraCSharpDriver. The error is "All hosts tried for query failed (tried :: SocketException 'A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond')".
I already have cassandra tested on main machine (x.x.x.1) and it worked, then I create 3 virtual machine with cassandra on it (x.x.x.2),(x.x.x.3),(x.x.x.4) but none of them worked on main machine. I even tried add all of the IP in the .yaml config file but doesn't seem work, althought x2, x3, x4 connected to each others on virtualbox with the same way. Is there anything I need to check in order to connect 3 virtual machine to main machine. Here is what I have done: config virt machine network to host-only; config virt machine IP to static; config .yaml file both virt and main machine; create keyspace, table. Here is the code create ISession
public static DataConnection Ins
{
get
{
if (_Ins == null)
_Ins = new DataConnection();
return _Ins;
}
set
{
_Ins = value;
}
}
private static DataConnection _Ins;
private DataConnection()
{
session = getConnect();
session.Execute("use KeySpace;");
}
public ISession session;
private string IP = "x.x.x.4";
private string Datacenter = "datacenter1";
public ISession getConnect()
{
return session = Cluster.Builder()
.AddContactPoints(IP)
.WithPort(9042)
.WithLoadBalancingPolicy(new DCAwareRoundRobinPolicy(Datacenter))
.Build()
.Connect();
}
And here the using part:
private void LoginBtnSubmit_Click(object sender, EventArgs e)
{
string query = "Query sth";
Cassandra.RowSet row = DataConnection.Ins.session.Execute(query);
if (row.FirstOrDefault() != null)
{
//Do sth
}
}
I have implemented the following version of ServiceStack .net Core Redis library:
ServiceStack.Redis.Core 5.9.2
I am using the library to access a Redis cache I have created to persist values for my AWS Serverless Application using .NET Core 3.1. I have paid for a commercial license for ServiceStack Redis.
Periodically and without warning, my application captures the following error when trying to create a Redis client:
Exception: System.Exception: No master found in: redis-cluster-api-prd-lcs.in-xxxxxxxx:6379
at ServiceStack.Redis.RedisResolver.CreateRedisClient(RedisEndpoint config, Boolean master) in C:\BuildAgent\work\b2a0bfe2b1c9a118\src\ServiceStack.Redis\RedisResolver.cs:line 116
at ServiceStack.Redis.RedisResolver.CreateMasterClient(Int32 desiredIndex) in C:\BuildAgent\work\b2a0bfe2b1c9a118\src\ServiceStack.Redis\RedisResolver.cs:line 142
at ServiceStack.Redis.RedisManagerPool.GetClient() in C:\BuildAgent\work\b2a0bfe2b1c9a118\src\ServiceStack.Redis\RedisManagerPool.cs:line 174
at LCSApi.UtilityCommand.Cache.IsCacheValueExists(String cacheKey, RedisManagerPool pool) in D:\a\1\s\testapi\Utility.cs:line 167
at LCSApi.Functions.LcsConfigurationSweeper(ILambdaContext context) in D:\a\1\s\testapi\Function.cs:line 2028
Exception: System.Exception: No master found in: redis-cluster-api-prd-lcs.in
Other times, the same code works fine. My implementation is quite simple:
private readonly RedisManagerPool _redisClient;
_redisClient = new RedisManagerPool(Environment.GetEnvironmentVariable("CACHE_URL") + ":" +
Environment.GetEnvironmentVariable("CACHE_PORT"));
public static T GetCacheValue<T>(string cacheKey, RedisManagerPool pool)
{
T cacheValue;
try
{
//StackExchange.Redis.IDatabase cache = Functions._redisConnect.GetDatabase();
//string value = cache.StringGet(cacheKey);
//cacheValue = (T)Convert.ChangeType(value, typeof(T));
using (var client = pool.GetClient())
{
client.RetryCount = Convert.ToInt32(Environment.GetEnvironmentVariable("CACHE_RETRY_COUNT"));
client.RetryTimeout = Convert.ToInt32(Environment.GetEnvironmentVariable("CACHE_RETRY_TIMEOUT"));
cacheValue = client.Get<T>(cacheKey);
}
}
catch (Exception ex)
{
//Console.WriteLine($"[CACHE_EXCEPTION] {ex.ToString()}");
cacheValue = GetParameterSSMFallback<T>(cacheKey);
//Console.WriteLine($"[CACHE_EXCEPTION] Fallback SSM parameter --> {cacheValue}");
}
return cacheValue;
}
It happens enough I've had to write a 'fallback' routine to fetch the value from the AWS Parameter Store where it originates from. Not ideal. Here is the Redis configuration:
I can find next to nothing about this error online anywhere. I've tried to sign up to the ServiceStack forums without success, it won't let me sign up for some reason, even though I have a commercial license. Can anyone assist?
The error is due to the network instance not connecting to a master instance as identified by the redis ROLE command. This could be happening during an ElastiCache failover where it eventually appears that the master instance will return under the original DNS name:
Amazon ElastiCache for Redis will repair the node by acquiring new service resources, and will then redirect the node's existing DNS name to point to the new service resources. Thus, the DNS name for a Redis node remains constant, but the IP address of a Redis node can change over time.
ServiceStack.Redis will try to connect to a master instance using all specified master connections (typically only 1). If it fails to connect to a master instance it has to give up as the client expects to perform operations on the read/write master instance.
If it's expected the master instance will return under the same DNS name we can use a custom IRedisResolver to continually retry connecting on the same connection for a master instance for a specified period of time, e.g:
public class ElasticCacheRedisResolver : RedisResolver
{
public override RedisClient CreateRedisClient(RedisEndpoint config, bool master)
{
if (master)
{
//ElastiCache Redis will failover & retain same DNS for master
var firstAttempt = DateTime.UtcNow;
Exception firstEx = null;
var retryTimeSpan = TimeSpan.FromMilliseconds(config.RetryTimeout);
var i = 0;
while (DateTime.UtcNow - firstAttempt < retryTimeSpan) {
try
{
var client = base.CreateRedisClient(config, master:true);
return client;
}
catch (Exception ex)
{
firstEx ??= ex;
ExecUtils.SleepBackOffMultiplier(++i);
}
}
throw new TimeoutException(
$"Could not resolve master within {config.RetryTimeout}ms RetryTimeout", firstEx);
}
return base.CreateRedisClient(config, master:false);
}
}
Which you configure with your Redis Client Manager, e.g:
private static readonly RedisManagerPool redisManager;
redisManager = new RedisManagerPool(...) {
RedisResolver = new ElasticCacheRedisResolver()
};
Note: there you should use only 1 shared instance of Redis Client Managers like RedisManagerPool so the share the same connection pool. If the class containing the redisManager is not a singleton it should be assigned to a static field ensuring the same singleton instance is used to retrieve clients.
I need to submit a custom Remote id when connecting to a IKEv2-VPN created with DotRas but I haven't figured out any way of doing this.
Remote id is submitted, however it's just the IP that is submitted. I need to customize this.
This is the code that creates the connection:
private void CreateConnection(String connectionName)
{
this.rasPhoneBook.Open(PHONEBOOK_PATH);
RasEntry entry = RasEntry.CreateVpnEntry(connectionName, SERVER_ADDRESS,
RasVpnStrategy.IkeV2Only,
RasDevice.Create(connectionName, RasDeviceType.Vpn));
this.rasPhoneBook.Entries.Add(entry);
}
And this is where I connect:
private void Connect()
{
// disconnect any lingering connections before connecting
this.Disconnect();
this.rasDialer.EntryName = this.serviceNameTextBox.Text;
this.rasDialer.PhoneBookPath = PHONEBOOK_PATH;
this.rasDialer.Credentials = new NetworkCredential(this.usernameTextBox.Text,
this.passwordTextBox.Text);
this.rasDialer.DialAsync();
}
Thanks for any help solving this.
I am running integration tests against an Azure Redis Cache. This is my very straightforward cache implementation:
public class RedisCacheEngine : ICacheEngine
{
private static readonly Lazy<ConnectionMultiplexer> LazyConnection = new Lazy<ConnectionMultiplexer>(() =>
{
var config = new ConfigurationService();
var connectionString = config.Get("Redis.ConnectionString");
var connection = ConnectionMultiplexer.Connect(connectionString);
return connection;
});
private static ConnectionMultiplexer Connection => LazyConnection.Value;
public TValue Get<TValue>(string key) where TValue : class
{
var redisValue = Connection.GetDatabase().StringGet(key);
return redisValue == RedisValue.Null
? default(TValue)
: JsonConvert.DeserializeObject<TValue>(redisValue);
}
public void Set<TValue>(string key, TValue value) where TValue : class =>
Connection.GetDatabase().StringSet(key, JsonConvert.SerializeObject(value));
public void Remove(string key) => Connection.GetDatabase().KeyDelete(key);
}
When I look at the connection object in the debugger, its failureMessage field reads "SocketFailure on PING". I don't believe the server is timing out, as the timeout window is a generous five seconds and I'm on a fast system, with a fast connection.
The connection string is a standard Azure Redis Cache string, of the form
myapp.redis.cache.windows.net:6380,password=___,ssl=True,abortConnect=False
I have tried setting ssl = False, but without success.
I would ideally like to be able to run these tests on my build environment, but at the moment I can't retrieve a working connection. I can't see anything obvious that I may be missing in the documemtation. Are there any checks I can run to ensure I'm doing the right thing?
is it possible to connect to the cache in an integration test?
Yes, I do a demo with your mentioned code just using connectionString directly, it works correctly on my side.
private static readonly Lazy<ConnectionMultiplexer> LazyConnection = new Lazy<ConnectionMultiplexer>(() =>
{
var connectionString = "mytest.redis.cache.windows.net:6380,password=xxxxxxxx,ssl=True,abortConnect=False";
var connection = ConnectionMultiplexer.Connect(connectionString);
return connection;
});
According to exception message SocketFailure on PING, I assume that your development environment firewall which is blocking port 6379, 6380.
If your redis service is Premium pricing tier, please have a check whether there is a firewall rule that blocks the client connection.
If your network is behind a firewall, please have a try to make sure the ports are open. Or please have a try to use another network environment.
The exception is Remoting Exception - Authentication Failure. The detailed message says "Unable to read data from the transport connection: the connection was closed."
I'm having trouble with creating two simple servers that can comunicate as remote objects in C#. ServerInfo is just a class I created that holds the IP and Port and can give back the address. It works fine, as I used it before, and I've debugged it. Also the server is starting just fine, no exception is thrown, and the channel is registered without problems. I'm using Forms to do the interfaces, and call some of the methods on the server, but didn't find any problems in passing the parameters from the FormsApplication to the server when debugging. All seems fine in that chapter.
public ChordServerProgram()
{
RemotingServices.Marshal(this, "PADIBook");
nodeInt = 0;
}
public void startServer()
{
try
{
serverChannel = new TcpChannel(serverInfo.Port);
ChannelServices.RegisterChannel(serverChannel, true);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
I run two instances of this program. Then startNode is called on one of the instances of the application. The port is fine, the address generated is fine as well. As you can see, I'm using the IP for localhost, since this server is just for testing purposes.
public void startNode(String portStr)
{
IPAddress address = IPAddress.Parse("127.0.0.1");
Int32 port = Int32.Parse(portStr);
serverInfo = new ServerInfo(address, port);
startServer();
//node = new ChordNode(serverInfo,this);
}
Then, in the other istance, through the interface again, I call another startNode method, giving it a seed server to get information from. This is where it goes wrong. When it calls the method on the seedServer proxy it just got, a RemotingException is thrown, due to an authentication failure. (The parameter I'll want to get is the node, I'm just using the int to make sure the ChordNode class has nothing to do with this error.)
public void startNode(String portStr, String seedStr)
{
IPAddress address = IPAddress.Parse("127.0.0.1");
Int32 port = Int32.Parse(portStr);
serverInfo = new ServerInfo(address, port);
IPAddress addressSeed = IPAddress.Parse("127.0.0.1");
Int32 portSeed = Int32.Parse(seedStr);
ServerInfo seedInfo = new ServerInfo(addressSeed, portSeed);
startServer();
ChordServerProgram seedServer = (ChordServerProgram)Activator.GetObject(typeof(ChordServerProgram), seedInfo.GetFullAddress());
// node = new ChordNode(serverInfo,this);
int seedNode = seedServer.nodeInt;
// node.chordJoin(seedNode.self);
}
Try setting the ensureSecurity to false, and it should start working.
ChannelServices.RegisterChannel(serverChannel, false);
You've specified that security is a must on your Remoting server in startServer() with:
ChannelServices.RegisterChannel(serverChannel, true);
Yet the 'client' end does not specify security, hence the authorisation error. You need to specify tcp channel security on both ends unless the server security setting is set to 'false'. In your second startNode method you need to do the following before using Activator.GetObject, note no port specified on the TcpChannel unlike the server end:
TcpChannel ClientChan = new TcpChannel();
ChannelServices.RegisterChannel(ClientChan, true);
Furthermore, unless you're doing it in some code you haven't given us, you also do not seem to have registered a well known service type server side, although you say it's been working in the debugger so maybe that's not necessary in the case. See MSDN on RegisterWellKnownServiceType.