I'm trying to work out how to use the CrmService to close a Task in MS CRM 4.0
I've tried to use the SetStateTaskRequest to set a Task's state and status to TaskState.Completed and 5. I also tried TaskState.Completed and -1, but no dice there either.
Either way, I only receive the ever-helpful "Server was unable to process request" exception on the CrmService.Execute attempt.
I can create and update Tasks as freely as I please. But I can't seem to set them to completed. It's frustrating.
I noticed that I can only set the state of a Task to Completed in CRM through the Close Task action. I was wondering if there is a separate CrmService call that I need to make to perform the Close Task action, rather than going through the CrmService.Execute method.
Oh: I'm logging into the CrmService with full permissions. So I can't see that it would be a permissions issue on the task item.
I can't think what else could be causing this issue. Any advice or even just a point in the right direction would be very much appreciated.
FIRST EDIT:
Thanks to grega g's answer for getting me to check the Detail field of the exception.
I now have a more detailed exception message. In XML Form:
<error>
<code>0x80040203</code>
<description>Invalid format of input XML for request SetStateTask: required field 'EntityId' is missing.</description>
<type>Platform</type>
</error>
Which is bizarre - consider my code (almost identical to greg g's:
SetStateTaskRequest request = new SetStateTaskRequest();
request.EntityID = gTaskId;
request.TaskState = TaskState.Completed;
// ETaskStatusCode is an enumeration of the status codes taken from the StringMap in CRM.
//
// ETaskStatusCode.Completed = 5 - I can confirm this is the accurate status value for a Closed Task.
//
// Also, I have attempted this code with -1, which the documentation claims should cause the status
// to automatically be set to the default status for the supplied state. No change there.
request.TaskStatus = (int)ETaskStatusCode.Completed;
SetStateTaskResponse response = CRMManager.CrmService.Execute(request) as SetStateTaskResponse;
Also, just to confirm that I have the right status code (and also share something I've found very useful when dealing with MS CRM), here's the SQL I use to determine the values for entity statuses.
SELECT
MSE.ObjectTypeCode,
MSE.PhysicalName,
SM.AttributeName,
SM.Value,
SM.AttributeValue
FROM MetadataSchema.Entity MSE
INNER JOIN StringMap SM on MSE.ObjectTypeCode = SM.ObjectTypeCode
ORDER BY MSE.PhysicalName, SM.AttributeName, SM.AttributeValue
I can confirm from the MS CRM web interface that the Status value that is associated with a Completed task is also named Completed. I can confirm from the SQL above that the value of this status, for a Task, is 5 - this is the value passed in from my Enum.
I can also confirm that gTaskId is being set to a valid Guid that references a Task that actually does exist, and is open at the time the close is attempted.
Curiouser and curiouser. Any thoughts?
Use SetStateTaskRequest class.
SetStateTaskRequest task2Close = new SetStateTaskRequest();
task2Close.EntityId = <taskGuid>
task2Close.TaskState = TaskState.Completed;
task2Close.TaskStatus = <some value>
try
{
SetStateTaskResponse r = (SetStateTaskResponse) crmSvc.Execute(task2Close);
}
catch (SoapException e)
{
//Use e.Details for more info than "server was unable ..."
}
This code should work (or let you see why error occurs)
Are you sure that when you are trying to close task you're passing status value which is valid for Completed state? Different status codes are only valid with their corresponding state codes. Can you add your source code and a portion of your state entity customization?
Found it!
Okay - reviewing my code above and the error message closely, my CrmService contained the property EntityID - but the exception was that the property EntityId was missing.
Somehow, my CrmService had its EntityId property renamed to EntityID.
Renaming the property fixed the problem. I still have no idea how that happened in the first place.
To be safe, I'll regenerate a new Service proxy to make sure that my properties are correctly named.
Looking through the code, it seems that someone did a find-and-replace on 'Id' and turned it into 'ID' - which incidentally is the naming convention in my workplace for Property fields that represent primary keys.
Thanks again to grega g for pointing out that the Detail property had the extra information I needed.
Related
I have working code that updates users names and supervisors with data from an HR SQL database. Everything works fine until I try to update the supervisor of a user who doesn't have a manager in Google. The object comes back with the UserToUpdate.Relations equal to null. It seems like I should be able to create a relation, but when I attempt to add the UserRelation item to the User, it errors with a "System.NullReferenceException: 'Object reference not set to an instance of an object.'" error. Any advice? Is there a way to add a relation to a user if they don't already have one?
code I'm running:
User UpdateUser = service.Users.Get(sUserEmail).Execute();
//code here to look up data in sql
UserRelation UR = new UserRelation();
UR.Type = "manager";
UR.Value = sManagersEmail;
UpdateUser.Relations.Add(UR); //this is where it fails
service.Users.Update(UpdateUser, sUserEmail).Execute();
I've also tried using the .Insert method instead of .Add:
UpdateUser.Relations.Insert(0,UR); //this also fails
to no avail -- same result.
For users that already have a manager, this works:
UpdateUser.Relations[0].value = sManagersEmail;
I can't find any further reference to do anything with .Net; I see how to do it with a JSON post outside .net's API, but it sure seems like I shouldn't have to do that...
Thank you!
you should check if the relations property on the user object is not null, otherwise instantiate an empty list, to which you will add the new relationship object.
try to use this in place of the line of code that fails:
if(UpdateUser.Relations == null){
UpdateUser.Relations = new List<UserRelation>();
}
UpdateUser.Relations.Add(UR);
I'm having trouble with passing in parameters to a get request. This request is intended to return a list of warehouses after the user entered some search parameters such as Date, State, ZIP and/or warehouse number, which is the only mandatory field. So when the search button is pressed the query is executed, but im getting this error:
2021-04-19 15:49:00 +0000
2021-11-02 13:06:44.670511-0600 WAREHOUSE_IOS-Master[3142:186324] GET method must not have a body
2021-11-02 13:06:44.670799-0600 WAREHOUSE_iOS-Master[3142:186324] Task <C7839029-C527-490E-8747-137012285F14>.<3> finished with error [-1103] Error Domain=NSURLErrorDomain Code=-1103 "resource exceeds maximum size" UserInfo={NSLocalizedDescription=resource exceeds maximum size,
error: invalidResponse
Okay so what im doing is passing a body to the get request that includes the search parameters as such:
struct WarehouseBody : Codable {
let dateRegistration : String?
let state : String?
let zip : String?
let warehouseNumber : String
}
and I'm expecting a response of this type:
struct WareHouseResponse: Codable {
let status: String?
let code: Int?
let responseCode, message: String?
let error: Bool?
let errorMessage: String?
let result: Result?
enum CodingKeys: String, CodingKey {
case status = "Status"
case code = "Code"
case responseCode = "ResponseCode"
case message = "Message"
case error = "Error"
case errorMessage = "ErrorMessage"
case result = "Result"
}
}
but according to what I've reading on other posts this is not the correct way of using a get request, but I really really need to do some testing. Is there a way that I can achieve this without needing to alter the backend? Just to mention that I ´m also the developer of the backend (c# using .net framework and dapper)so if the easiest way is to achieve this is by altering it I can also do that. Any ideas are very much appreciated.
On the backend I was thinking of implementing a post Request that sends the search parameters to the server and then a get request that pulls out the requested information, but I don't know if that's the correct approach. But this not feasible at the moment because the Web API are already publish and I cannot re publish with the changes at the moment, and is really urgent to test the response so that's why I would like to know if all this can be done from the front end first. Thank you very much for all the help!
Thank you very much for your help!
EDIT: Also I forgot to mention that the api has been previously tested on POSTMAN and is working perfectly.
Since iOS 13. you cannot pass in parameters to a GET request. There’s no easy way around this. You need to change your request from a GET to a POST on the backend. In my case, this was an easy task because I had access to the API source— but, if you don’t, just ask the backend team to change it, and pass in the parameters as in any other POST request. That should work.
Lately the Nemiro.OAuth api is throwing null reference exceptions for some reason. After getting the lates versoin Nemiro.OAuth v1.12.0 and Nemiro.OAuth.loginForms v1.6.0 it started to behave like this, haven't changed my implemented logic in any way.
My file structure in dropbox:
https://www.dropbox.com/home/Apps/MyApplication/MyFolder/SubFolder/Some%20folder1/MyFiles
Old and new uri:
/MyFolder/SubFolder/Some folder1/MyFiles/somefile.png
When I call OAuthUtility.Post it shows following error message:
I'm using following logic to handle the request:
string oldUri = oldPath.ToUri();
string newUri = newPath.ToUri();
var paramCollection = new HttpParameterCollection
{
{"access_token", ACCESS_TOKEN},
{"from_path", oldUri },
{"to_path", newUri },
{"root","auto"}
};
OAuthUtility.Post
(
"https://api.dropboxapi.com/1/fileops/move",
paramCollection
);
I already checked that file exists in dropbox, my access token is valid, also, as you can see the path is correct.. Also it fails for other operations like
https://content.dropboxapi.com/1/files_put/auto{0}/{1}
What could cause this?
Could it be something with new Dropbox api V2?
Update
It actually works, but throws null reference exception at the same time..
That is pretty annoying, that means I need to wrap each operation in try catch block. Also, when I created new console application and executed the same code, it worked without any exceptions. Which means, something is wrong in my project.
0. Dropbox API v1 has been deprecated:
https://blogs.dropbox.com/developers/2016/06/api-v1-deprecated/
...In order to provide our developers with the most up-to-date features and support a single, consistent platform, we’ll be turning off API v1 a year from now, on 6/28/2017.
It remains approximately two months :-) I recommend switching to the new version of the API.
1. Do you pass the URI? But why are you doing this? Just use a string path relative to the root directory of the application. I tried to use a URI, this code does not work for me, the server returns an error 404.
I used relative paths and checked the code and do not see any problems.
If possible, show the full code in which the problem occurs.
Or you can send the project to me by email: aleksey.nemirogmail.com
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();
}
I'm trying to put together a small app that will allow me to create events in Facebook. I've already got my Facebook app set up and have successfully tested a post to my feed through the application using the code below.
wc.UploadString("https://graph.facebook.com/me/feed", "access_token=" + AccessToken + "&message=" + Message);
When I try to take things to the next step, I've just hit a brick wall.
The code that I've written is here:
JavaScriptSerializer ser = new JavaScriptSerializer();
wc.UploadString("https://graph.facebook.com/me/events?" + "access_token=" + AccessToken, ser.Serialize(rawevent));
rawevent is a small object I wrote that puts together the elements of an event so I can pass it around my application.
I'm using a similar method using ser.Deserialize to parse the user data coming back from Facebook, so I believe this should work the other way too.
Setting the above code aside for a moment, I also have tried simply putting plain text in there in various formats and with differing levels of parameters, and nothing seems to work.
Is there something wrong with the way I'm approaching this? I've read over everything I could get my hands on, and very few of the samples out there that I could find deal with creating events, and when they do, they're not in C#.
I would appreciate any help on this. If you even just have a clean copy of JSON code that I can look at and see where mine should be tweaked I would appreciate it.
I have included a copy of what the ser.Serialize(rawevent) call produces below:
{"name":"Dev party!","start_time":"1308360696.86778","end_time":"1310952696.86778","location":"my house!"}
EDIT:
thanks to bronsoja below, I used the code below to successfully post an event to Facebook!
System.Collections.Specialized.NameValueCollection nvctest = new System.Collections.Specialized.NameValueCollection();
nvctest.Add("name", "test");
nvctest.Add("start_time", "1272718027");
nvctest.Add("end_time", "1272718027");
nvctest.Add("location", "myhouse");
wc.UploadValues("https://graph.facebook.com/me/events?" + "access_token=" + AccessToken, nvctest);
All the posting examples in the graph api examples in FB docs show using curl -F, which indicates values be POSTed as normal form data. Just key value pair like you did in your first example.
The error is likely due to sending JSON. If you are using WebClient you may be able to simply create a NameValueCollection with your data and use WebClient.UploadValues to send the request.
I've recently found that Facebook returns (#100) Invalid parameter when we are trying to post data when there is already a record on file with the same name. So for example, if you are creating a FriendList via the API, and the name is "foo", submitting another identical request for the same name will immediately return that error.
In testing events you probably deleted the "Dev party!" event after each test, or maybe changing the time since you don't want two events to collide. But I'm wondering if you duplicated your wc.UploadValues(...) statement just as a test if you would see that error again. You're either deleting your 'test' event or maybe changing names and didn't notice that two events with the same name might return the error.
What's really bad here is that the error comes back as a OAuthException, which seems very wrong. This isn't a matter of authentication or authorization, it's purely a data issue.
Facebook Engineers, if I'm right about how this works, it's a bug to return this error under these conditions, and this forum has many examples of related confusion. Please return more appropriate errors.