Caching behavior of the last Dynamics SDK is driving me crazy.
First, if you want to use CrmServiceClient to access different environments you have to use the parameter RequireNewInstance=True; in the connection string. If not, every instance of CrmServiceClient will use the same connection, even if you create and dispose instances to different environments.
Now, even if you use the RequireNewInstance=True; in the connection string I found that cache still occurs in some scenarios.
var client1 = new CrmServiceClient("RequireNewInstance=True;
Url=https://myCompany.crm.dynamics.com;
Username=myUser#myCompany.onmicrosoft.com; Password=myPassowrd;
AuthType=Office365");
//Now, client 2 points to a url that doesn’t exists:
var client2 = new CrmServiceClient("RequireNewInstance=True;
Url=https://xxx.crm.dynamics.com; Username=myUser#myCompany.onmicrosoft.com;
Password=myPassowrd; AuthType=Office365");
The client2 keeps using the first connection string, so you cannot determine if the new connection string is correct.
Any ideas how to test Dynamics Crm connections strings correctly in my asp.net application?
Late reply, but the behavior you're seeing is because when you're specifying an erroneous URL the discovery service is used to ascertain which instance to connect to.
To prevent this specify SkipDiscovery=True in your connection string:
var connectionString2 = #"AuthType=Office365;Url=https://FAKE.crm.dynamics.com;Username=USERNAME;Password=PASSWORD;RequireNewInstance=True;SkipDiscovery=True;";
Edit: SkipDiscovery is true by default starting with 9.0.7, kudos to #mwardm
I think I found the problem. It seems to only happens on Dynamics 365 online trials, that was the reason we were getting inconsistent results depending on the environment.
Apparently, the url doesn't need to be completely valid to establish a connection to a CRM online trial environment, as long as the credentials are valid and the url structure is kept.
Let's consider the following example:
var client1 = new CrmServiceClient("RequireNewInstance=True;
Url=https://fake.crm.dynamics.com;
Username=myUser#myCompany.onmicrosoft.com; Password=myPassowrd;
AuthType=Office365");
In this case I can substitute the "fake" part of the url with whatever I want, but still execute requests correctly using the CrmServiceClient service.
If I try to do this with another environment (e.g. 2015, on premise, not-trial crm online, etc.), the IsReady property of the CrmServiceClient would return false and I would get an error in the LastCrmError property.
Very weird behavior, and difficult to pinpoint.
Now that I think I understand the inconsistent behavior I know that finally it will not affect our clients, so I will mark this response as the answer even if I still do not know why we have different behavior between a trial and a normal environment..
I agree choosing to reuse the existing connection if you don't include RequireNewInstance=true seems counter-intuitive, but I can't reproduce what you're seeing. If I try the following from LinqPad crmSvcClient2 will print out errors and then throw a null ref on the Execute call (8.2.0.2 version of the SDK). With this version of the SDK you'll want to always check LastCrmError after connecting to see if the connection failed.
var connectionString = #"AuthType=Office365;Url=https://REAL.crm.dynamics.com;Username=USERNAME;Password=PASSWORD;RequireNewInstance=True;";
var connectionString2 = #"AuthType=Office365;Url=https://FAKE.crm.dynamics.com;Username=USERNAME;Password=PASSWORD;RequireNewInstance=True;";
using (var crmSvcClient = new CrmServiceClient(connectionString))
{
"crmSvcClient".Dump();
crmSvcClient.LastCrmError.Dump();
((WhoAmIResponse)crmSvcClient.Execute(new WhoAmIRequest())).OrganizationId.Dump();
crmSvcClient.ConnectedOrgFriendlyName.Dump();
}
using (var crmSvcClient2 = new CrmServiceClient(connectionString2))
{
"crmSvcClient2".Dump();
crmSvcClient2.LastCrmError.Dump();
((WhoAmIResponse)crmSvcClient2.Execute(new WhoAmIRequest())).OrganizationId.Dump();
crmSvcClient2.ConnectedOrgFriendlyName.Dump();
}
Related
So I have a few different parse servers setup.
One server is just to capture error logs from various applications (I have a LOT out there) in nice uniformed database.
So I might have a specific standalone data migration tool that if it encounters an error, will write out the exception into this Error_log parse table/class. No problem there.
But, if I have an app that uses a Parse Database for itself, I have not been able to figure out how to let it work on it's own parse server configuration for it's own stuff, but write out error logs to this other Parse server instance.
Yes... I could go through the trouble of writing out something via the REST api just for writing out logs,but I am I trying to avoid that and stick with native parse APIs for the particular platform I am on because of the benefits that the APIs give over REST (like save eventually for the none .NET stuff).
EDIT
Some clarification was requested so here I go...
On the app side of things (c# for this example but the same holds true for iOS etc)… I do the usual initialization of the Parse client as such …
ParseClient.Initialize(new ParseClient.Configuration
{
ApplicationId = "MyAppID",
WindowsKey = "MyDotNetKey",
Server = "www.myparseserver.com/app1"
});
So for all calls to save a parse object go through that parse client connection
But what I need to do would be something like this ….
//Main App cloud database
ParseClient1.Initialize(new ParseClient.Configuration
{
ApplicationId = "MyAppID",
WindowsKey = "MyDotNetKey",
Server = "www.myparseserver.com/app1"
});
ParseClient2.Initialize(new ParseClient.Configuration
{
ApplicationId = "MyAppID",
WindowsKey = "MyDotNetKey",
Server = "www.myparseserver.com/errorcollection"
});
try{
ParseConfig config = null;
config = await ParseConfig.GetAsync().ParseClient1;
} catch (Exception ex){
ParseObject MyError = new ParseObject("Error_Log");
MyError["Application"] = "My First App-App2";
MyError["Error"] = ex.message;
await MyError.Save().ParseClient2;
}
Yes - this is all fake code... my point is I want to be able to have multiple ParseClient instances in one app.
Now... I can simply write a routine that writes out errors that resets the ParseClient.Initialization to the error parse server instance and then redo it back to the original (primary app data) instance when it's done... but that is just asking for trouble in a multi threaded environment and will cause conflicts if some other thread in the app goes to write out parse data right at the moment the error method resets the init.
If ParseClient were IDisposable I could probably do that using :
ParseClient ParseErrorServer = new ParseClient();
ParseErrorServer.ApplicationId = "hmmm";
ParseErrorServer.WindwosKey= "hmmm";
ParseErrorServer.Server= "www.hmmm.com/errorcollection";
using ParseErrorServer {
//Do The Work
}
Is that clear as mud yet? ;P
Without alteration I believe none of the Parse SDKs have the ability to initialise multiple instances.
In the iOS SDK for example, is possible to make a new instance (say with a different server url) upon restarting the app but you cannot have multiple. There has also been discussion on the iOS SDK about being able to change the configuration without restart but no one has implemented this yet.
We would happily review a PR for this, however it would require a major and complex overhaul as you would have to manage cache, users etc across multiple instances.
I've searched without much success to the simplest (and yet working) example of an LDAP/AD Server for C#. Many libraries exist to connect to LDAP servers, but not the LDAP Server by itself (on C#).
I found however some information about it and even a post requesting a simple LDAP server that was answered "LDAP isn't simple"; and yet i read a lot of the RFC4511 and this sample code at GitHub Flexinet LDAP Server, but unfortunatly i don't have yet the knowledge to complete it's code.
My goal is not to make a fully functional LDAP server, but one that can at least do:
Serve as a login pool for softwares that allow it's users to be
registered and log on a AD/LDAP server (just check for login and
password for authentication).
Allow softwares like Outlook and Thunderbird to get a list of users (without passwords) with first and last name, e-mail address, phone number and department for contact list model.
No delete, add (or create), move, and other
functions are required since the main software that i aim to
integrate it with will do all the user and group management.
UPDATE
I'm trying to implement the Flexinet sample and adjust to that functionalities; as form of a question what should i do to change this function to prevent it from causing an exception (on the "var filter = searchRequest.ChildAttributes[6];" line it always breaks) when i call from a LDAP client software:
private void HandleSearchRequest(NetworkStream stream, LdapPacket requestPacket)
{
var searchRequest = requestPacket.ChildAttributes.SingleOrDefault(o => o.LdapOperation == LdapOperation.SearchRequest);
var filter = searchRequest.ChildAttributes[6];
if ((LdapFilterChoice)filter.ContextType == LdapFilterChoice.equalityMatch && filter.ChildAttributes[0].GetValue<String>() == "sAMAccountName" && filter.ChildAttributes[1].GetValue<String>() == "testuser") // equalityMatch
{
var responseEntryPacket = new LdapPacket(requestPacket.MessageId);
var searchResultEntry = new LdapAttribute(LdapOperation.SearchResultEntry);
searchResultEntry.ChildAttributes.Add(new LdapAttribute(UniversalDataType.OctetString, "cn=testuser,cn=Users,dc=dev,dc=company,dc=com"));
searchResultEntry.ChildAttributes.Add(new LdapAttribute(UniversalDataType.Sequence));
responseEntryPacket.ChildAttributes.Add(searchResultEntry);
var responsEntryBytes = responseEntryPacket.GetBytes();
stream.Write(responsEntryBytes, 0, responsEntryBytes.Length);
}
var responseDonePacket = new LdapPacket(requestPacket.MessageId);
responseDonePacket.ChildAttributes.Add(new LdapResultAttribute(LdapOperation.SearchResultDone, LdapResult.success));
var responseDoneBytes = responseDonePacket.GetBytes();
stream.Write(responseDoneBytes, 0, responseDoneBytes.Length);
}
The code is on the github link.
Finally i made a fork of the Flexinet LDAP Server on #Sammuel-Miranda/LdapServerLib and with the author's support and some changes and adaptations i completed this implementation. It responds to the bind and search calls and works perfectly for Outlook and Thunderbird to use as a shared address book.
I did not implemente however any ADD/MODIFY/DELETE request (but would not be hard to do) since i don't need then.
I found on the RFC4511 the explanation on how the search works ... and i'm "kind" of understanding it, not very well - and i see that the method implemented on the GitHub from Flexinet LDAP Server only answer to bind and search requests of one single user (since it's only a example implementation).
The client is requesting diferent calls to verify capabilities, structure and other info before making the search request itself. So i'll implement it all, one by one.
Still, if any other lib (in C#) exists, and anyone know about, would be better than writing a hole new server. If my implementation works, i'll fork it on github and share.
I'm trying to work through the hello world example on the Neo4j .Net driver page but every time I try to run the example, it spins for a while and then throws an exception:
Neo4j.Driver.V1.ServiceUnavailableException: 'Failed after retried for
5 times in 30000 ms. Make sure that your database is online and retry
again
I've confirmed my database is running as I can see it through the neo4j browser running at localhost:7474. I'm trying to create the connection as follows
// Invocation in Main method
using (var greeter = new HelloWorldExample("bolt://localhost:7474", "neo4j", "neo4j"))
{
greeter.PrintGreeting("Hello, World");
}
...
// Constructor for HelloWorldExample, and where it's getting hung
public HelloWorldExample(string uri, string user, string password)
{
_driver = GraphDatabase.Driver(uri, AuthTokens.Basic(user, password));
}
I've tried several different variants of the URI (such as using port 7687, like the example says, even though that's not where my instance is running) as well as trying to use http instead of bolt as the protocol (which threw a completely different error, saying that's not allowed) to no avail. Anyone know what I might be missing?
You are using the wrong port, that is the UI port. You need to connect to port 7687 (if you are using the defaults, which I assume you are)
using (var greeter = new HelloWorldExample("bolt://localhost:7687", "neo4j", "neo4j"))
{
greeter.PrintGreeting("Hello, World");
}
I'm following a tutorial on this link http://www.codeproject.com/KB/aspnet/ASPNETService.aspx
Now I'm stuck at these codes
private const string DummyPageUrl =
"http://localhost/TestCacheTimeout/WebForm1.aspx";
private void HitPage()
{
WebClient client = new WebClient();
client.DownloadData(DummyPageUrl);
}
My local application address has a port number after "localhost", so how can I get the full path (can it be done in Application_Start method)? I want it to be very generic so that it can work in any cases.
Thanks a lot!
UPDATE
I tried this in the Application_Start and it runs fine, but return error right away when published to IIS7
String path = HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority) + VirtualPathUtility.ToAbsolute("~/");
If it is calling back to the same server, perhaps use the Request object:
var url = new Uri(Request.Url, "/TestCacheTimeout/WebForm1.aspx").AbsoluteUri;
Otherwise, store the other server's details in a config file or the database, and just give it the right value.
But a better question would be: why would you talk via http to yourself? Why not just call a class method? Personally I'd be using an external scheduled job to do this.
You need an answer that works when you roll out to a different environment that maybe has a virtual application folder.
// r is Request.Url
var url = new Uri(r, System.Web.VirtualPathUtility.ToAbsolute("~/Folder/folder/page.aspx")).AbsoluteUri;
This will work in all cases and no nasty surprises when you deploy.
I suspect you're using the ASP.NET development server that's built-in to Visual Studio, which has a tendency to change port numbers by default. If that's the case, then you might try simply configuring the development server to always use the same port, as described here. Then just add the port number to your URL, like so:
private const string DummyPageUrl =
"http://localhost:42001/TestCacheTimeout/WebForm1.aspx";
This is a follow-up to Choosing a Connection String based on kind of request for which I got no answer and what I thought worked doesn't.
I have a webservice that needs to choose a specific connection string based on the user calling it from a browser or from a client application.
I tried:
HttpContext.Current != null? ConnectionStrings["Website"].ConnectionString : ConnectionStrings["Client"].ConnectionString
but realized that at some point even if I'm using the client application, there is some HttpContext (if someone can explain why it'd be great) but the Browser field under Request is "Unknown". So, then I tried:
if ( HttpContext.Current != null )
{
if ( HttpContext.Current.Request.Browser != "Unknown" )
{
//browser connection string here
}
else
//client app connection string here
}
else
//client app connection string here
This worked wonders when debugging, but on testing environment it still points to Browser connection string even when calling from the client app, as if at some point the Browser isn't "Unknown" ...
Is there a MUCH easier/simpler way to do this? The way I'm doing it seems really ugly.
I'm quite desperate at the moment as I have no idea why this is happening..
Rather than detecting and switching on the browser type, consider these two suggestions:
Add Custom Request Headers
In your various callers, define a new custom header in your Http request.
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.Headers.Add("CallerType", "ClientApp"); // "Browser", etc.
Then you know exactly and reliably what type of client is calling. This would be hard to get wrong, and couldn't be spoofed/mistaken.
Include The Caller Type in the QueryString
myService.asmx?BrowserType=1
Add a simple new querystring parameter to your .asmx webmethod. This will work just the same in a controlled environment, but if other users/developers get it wrong, or malform the expected values, you'd have to take other measures to correct/handle.
Both allow you to easily determine the connString on the incoming value. Perhaps the absense of a modifier/header, you could assume a default. Your sample question has 2 basic outcomes, and either suggested solution will be easy to extend (browser, client app, iPhone, whathaveyou).