I want to create an Azure Service Bus MessagingFactory instance from a connection string and specific the BatchFlushInterval setting.
The factory method on MessagingFactory that takes a connection string does not take a MessagingFactorySettings instance.
The factory method on MessagingFactory that takes a MessagingFactorySettings instance does not take a connection string.
The closest I've come is this:
var connectionStringBuilder = new ServiceBusConnectionStringBuilder(connectionString);
var messagingSettings = new MessagingFactorySetttings
{
TokenProvider = TokenProvider.CreateSharedSecretTokenProvider(connectionStringBuilder.SharedSecretIssuerName, connectionStringBuilder.SharedSecretIssuerSecret),
NetMessagingTransportSettings =
{
BatchFlushInterval = TimeSpan.FromMilliseconds(100) // <-- This is the setting I want to specify.
}
};
var messagingFactory = MessagingFactory.CreateFromConnectionString(connectionStringBuilder.Endpoints, messagingSettings);
But that only works if you know that's the specific token provider information provided in the connection string. If it does something else, like use one of the other five methods of providing tokens, then this code fails.
How can you create a MessagingFactory instance from a connection string and specify the BatchFlushInterval?
The way I found to do it is by using the token provider from the namespace manager. So:
var namespaceMngr = NamespaceManager.CreateFromConnectionString(namespaceConnString);
MessagingFactorySettings mfs = new MessagingFactorySettings();
mfs.TokenProvider = namespaceMngr.Settings.TokenProvider;
mfs.NetMessagingTransportSettings.BatchFlushInterval = TimeSpan.FromSeconds(timeToFlush);
MessagingFactory mf = MessagingFactory.Create(namespaceMngr.Address, mfs);
If you are trying to set the AmqpTransportSettings.BatchFlushInterval instead of the NetMessagingTransportSettings.BatchFlushInterval then I can't help you, I actually stumbled on this post looking for an answer. Trying to change the AmqpTransportSettings.BatchFlushInterval doesn't seem to stick to the MessageFactory even if the MessageFactorySettings reflect the change.
JordanSchillers answer fixes the token provider issue but my address was now using port 9355 instead of 9354.
I ended using a mixture of the ServiceBusConnectionStringBuilder and the NamespaceManager:
var serviceBusConnectionString = new ServiceBusConnectionStringBuilder(connection.ConnectionString);
MessagingFactorySettings factorySettings = new MessagingFactorySettings();
factorySettings.TransportType = serviceBusConnectionString.TransportType;
//Use the namespacemanager to create the token provider.
var namespaceManager = NamespaceManager.CreateFromConnectionString(connection.ConnectionString);
factorySettings.TokenProvider = namespaceManager.Settings.TokenProvider;
factorySettings.NetMessagingTransportSettings.BatchFlushInterval = TimeSpan.FromMilliseconds(batchTimeInMs);
MessagingFactory factory = MessagingFactory.Create(serviceBusConnectionString.Endpoints, factorySettings);
return factory.CreateTopicClient(topicName);
Related
The documentation shows how to make a transfer from one wallet to another. In one account.
// Initialize the rpc client and a wallet
var rpcClient = ClientFactory.GetClient(Cluster.TestNet);
var wallet = new Wallet();
// Get the source account
var fromAccount = wallet.GetAccount(0);
// Get the destination account
var toAccount = wallet.GetAccount(1);
// Get a recent block hash to include in the transaction
var blockHash = rpcClient.GetRecentBlockHash();
// Initialize a transaction builder and chain as many instructions as you want before building the message
var tx = new TransactionBuilder().
SetRecentBlockHash(blockHash.Result.Value.Blockhash).
SetFeePayer(fromAccount).
AddInstruction(MemoProgram.NewMemo(fromAccount, "Hello from Sol.Net :)")).
AddInstruction(SystemProgram.Transfer(fromAccount, toAccount.GetPublicKey, 100000)).
Build(fromAccount);
var firstSig = rpcClient.SendTransaction(tx);
How to make a transfer to another account?
Do I need to know the private key of the account to which I will transfer?
Your example has all of the pieces you need. To transfer to another account, you need to create a transaction (using TransactionBuilder), and specifically add a SystemProgram.Transfer instruction to your transaction. Also, in your example, you're sending from fromAccount, which has the private key, to toAccount.PublicKey. You're using the PublicKey of toAccount, so no need for the private key of the recipient.
Note that the example appears to be incorrect, so you should base your code from this example instead: https://github.com/bmresearch/Solnet/blob/8369ac166ed90a7e6b07060178ed70745bd97bc3/src/Solnet.Examples/TransactionBuilderExample.cs#L22
I have a need to manage Kerberos Resource Based Delegation in C# (I know it's easier in Powershell but that is not the requirement). The attribute on the user/computer/service accounts is msDS-AllowedToActOnBehalfOfOtherIdentity, but this seems to be some COM object which I can't seem to deal with in C#:
static void Main(string[] args)
{
string ou = #"OU=some,OU=ou,DC=corp,DC=com";
string cn = #"someaccount";
DirectoryEntry de = new DirectoryEntry();
de.Username = #"CORP\userwithOUrights";
de.Password = #"password";
de.AuthenticationType = AuthenticationTypes.Secure;
de.Path = $"LDAP://CN={cn},{ou}";
Object a = de.Properties["msDS-AllowedToActOnBehalfOfOtherIdentity"];
}
After this, a doesn't seem to be anything I can do much with, unlike other properties. It is some COM object and I need to get the accounts which are in there. Powershell reports that this property returns a System.DirectoryServices.ActiveDirectorySecurity object and I see useful methods in this class for decoding the binary format which is stored in AD etc. But this does not seem to be the return type from the property call in C#.
Update: All of this is now better documented in an article on my website: Handling NT Security Descriptor attributes
According to this the "attribute syntax" for that attribute is 2.5.5.15. According to this, that means it's a "String(NT-Sec-Desc)". According to this, that means it's a IADsSecurityDescriptor COM object.
You can add a COM reference in your project to "Active DS Type library" and cast it directly to IADsSecurityDescriptor, like this:
var act = (ActiveDs.IADsSecurityDescriptor)
de.Properties["msDS-AllowedToActOnBehalfOfOtherIdentity"].Value;
Console.WriteLine(act.Owner);
The Owner property gives you a DOMAIN\Username.
According to this random code I found, it seems you can also use the RawSecurityDescriptor class to interact with it. There is a constructor that takes a plain string, but you also can't seem to get the raw string from the attribute from DirectoryEntry.
But I did remember that sometimes DirectorySearcher will give you values in a different type than DirectoryEntry (doesn't make sense, but it's true). That appears to be true here. DirectorySearcher gives this attribute to you as a byte[], and RawSecurityDescriptor does have a constructor that takes a byte[].
So it seems you can do something like this:
string ou = #"OU=some,OU=ou,DC=corp,DC=com";
string cn = #"someaccount";
var search = new DirectorySearcher(new DirectoryEntry($"LDAP://{ou}"), $"(cn={cn})");
search.PropertiesToLoad.Add("msDS-AllowedToActOnBehalfOfOtherIdentity");
var result = search.FindOne();
var act = new RawSecurityDescriptor(
(byte[]) result.Properties["msDS-AllowedToActOnBehalfOfOtherIdentity"][0], 0);
Console.WriteLine(act.Owner);
//make changes to act.DiscretionaryAcl
byte[] descriptor_buffer = new byte[act.BinaryLength];
act.GetBinaryForm(descriptor_buffer, 0);
var de = result.GetDirectoryEntry();
de.Properties["msDS-AllowedToActOnBehalfOfOtherIdentity"].Value = descriptor_buffer;
de.CommitChanges();
In this, act.Owner is an account SID.
Using System.DirectoryServices, one can get the highestCommittedUSN this way:
using(DirectoryEntry entry = new DirectoryEntry("LDAP://servername:636/RootDSE"))
{
var usn = entry.Properties["highestCommittedUSN"].Value;
}
However, I need to get this information from a remote ADLDS using System.DirectoryServices.Protocols, which does not leverage ADSI. Following is a simplified code sample of what I'm attempting to do:
using(LdapConnection connection = GetWin32LdapConnection())
{
var filter = "(&(highestCommittedUSN=*))";
var searchRequest = new SearchRequest("RootDSE", filter, SearchScope.Subtree, "highestCommittedUSN");
var response = connection.SendRequest(searchRequest) as SearchResponse;
var usn = response.Entries[0].Attributes["highestCommittedUSN"][0];
}
Unfortunately this kicks back a "DirectoryOperationException: The distinguished name contains invalid syntax." At first I thought there might be something wrong in GetWin32LdapConnection() but that code is called in numerous other places to connect to the directory and never errors out.
Any ideas?
Thanks for the idea, Zilog. Apparently to connect to the RootDSE, you have to specify null for the root container. I also switched the filter to objectClass=* and the search scope to "base." Now it works!
using(LdapConnection connection = GetWin32LdapConnection())
{
var filter = "(&(objectClass=*))";
var searchRequest = new SearchRequest(null, filter, SearchScope.Base, "highestCommittedUSN");
var response = connection.SendRequest(searchRequest) as SearchResponse;
var usn = response.Entries[0].Attributes["highestcommittedusn"][0];
}
I hope this saves someone else some time in the future.
I am trying Proof of Concepts based on code at http://msdn.microsoft.com/en-us/library/windowsazure/gg618003. This cache is accesible if I use app.config settings. When I switched the application to use programatic configuration, I consistently get this error. I have already tried Azure cache programatically configuration fail to verify and many other solutions to no avail.
Here's my code snippet.
{code}
String acsKey = "AcsKey removed intentionaly";
DataCacheFactoryConfiguration cacheFactoryConfiguration;
DataCacheSecurity dataCacheSecurity;
DataCacheServerEndpoint[] serverEndpoints = new DataCacheServerEndpoint[1];
SecureString secureAcsKey = new SecureString();
serverEndpoints[0] = new DataCacheServerEndpoint("EndPont removed intentionaly", 22243);
//
// Create SecureString from string
//
foreach (char keyChar in acsKey)
{
secureAcsKey.AppendChar(keyChar);
}
secureAcsKey.MakeReadOnly();
dataCacheSecurity = new DataCacheSecurity(secureAcsKey);
//
// Initialize Factory Configuration
//
cacheFactoryConfiguration = new DataCacheFactoryConfiguration(); // This line throws exception. Note that the key is yet to be assigned to SecurityProperties as per documentation.
cacheFactoryConfiguration.Servers = serverEndpoints;
cacheFactoryConfiguration.SecurityProperties = dataCacheSecurity;
_cacheFactory = new DataCacheFactory(cacheFactoryConfiguration);
_cache = _cacheFactory.GetDefaultCache();
{code}
Try passing all the params at creation and not post creation?
var configFactory = new DataCacheFactoryConfiguration
{
Servers =
new List<DataCacheServerEndpoint>
{new DataCacheServerEndpoint(cacheServer, cachePort)},
SecurityProperties =
new DataCacheSecurity(Encryption.CreateSecureString(cacheAuthorization),
true)
};
I would like to connect to the database specified in the connection string, without specifying it again in GetDatabase.
For example, if I have a connection string like this;
mongodb://localhost/mydb
I would like to be able to db.GetCollection("mycollection") from mydb.
This would allow the database name to be configured easily in the app.config file.
Update:
MongoServer.Create is obsolete now (thanks to #aknuds1). Instead this use following code:
var _server = new MongoClient(connectionString).GetServer();
It's easy. You should first take database name from connection string and then get database by name. Complete example:
var connectionString = "mongodb://localhost:27020/mydb";
//take database name from connection string
var _databaseName = MongoUrl.Create(connectionString).DatabaseName;
var _server = MongoServer.Create(connectionString);
//and then get database by database name:
_server.GetDatabase(_databaseName);
Important: If your database and auth database are different, you can add a authSource= query parameter to specify a different auth database. (thank you to #chrisdrobison)
From docs:
NOTE If you are using the database segment as the initial database to
use, but the username and password specified are defined in a
different database, you can use the authSource option to specify the
database in which the credential is defined. For example,
mongodb://user:pass#hostname/db1?authSource=userDb would authenticate
the credential against the userDb database instead of db1.
In this moment with the last version of the C# driver (2.3.0) the only way I found to get the database name specified in connection string is this:
var connectionString = #"mongodb://usr:pwd#srv1.acme.net,srv2.acme.net,srv3.acme.net/dbName?replicaSet=rset";
var mongoUrl = new MongoUrl(connectionString);
var dbname = mongoUrl.DatabaseName;
var db = new MongoClient(mongoUrl).GetDatabase(dbname);
db.GetCollection<MyType>("myCollectionName");
With version 1.7 of the official 10gen driver, this is the current (non-obsolete) API:
const string uri = "mongodb://localhost/mydb";
var client = new MongoClient(uri);
var db = client.GetServer().GetDatabase(new MongoUrl(uri).DatabaseName);
var collection = db.GetCollection("mycollection");
The answer below is apparently obsolete now, but works with older drivers. See comments.
If you have the connection string you could also use MongoDatabase directly:
var db = MongoDatabase.Create(connectionString);
var coll = db.GetCollection("MyCollection");