I was looking at the Onscreen Reference to see if there's an XML request for querying jobs. I found that there's just customer query request CustomerQueryRq and that too doesn't return the child jobs that it has.
Supposing this is how the customers & jobs centre looks like:
- Customer 1
-- Job 1
-- Job 2
-- Job 3
I was able to use CustomerQueryRq and get the details for Customer 1, but couldn't find anything for retrieving Job 1.
So my question is how do I query for a job and get the parent customer it's in? I'd really appreciate any help.
EDIT: Posting my QBXML request:
<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="13.0"?>
<QBXML>
<QBXMLMsgsRq onError="continueOnError">
<CustomerQueryRq requestID="1">
<FullName>Customer name</FullName>
</CustomerQueryRq>
</QBXMLMsgsRq>
</QBXML>
The Customer name has child jobs and I'd like to query those.
ICustomerQuery returns the list of Jobs along with the Customers list. There isn't a separate query object for Jobs. Each job has a customer as a parent. Hence, you can also retrieve the associated customer for the job.
Here's an example: I have a job J1 associated with a customer C1 in my company file. In the below C# code sample, I create a customer query object (using QB SDK 13.0) and iterate over the results. I get two results in the customer list( C1 and J1 ):
using QBXMLRP2Lib;
using Interop.QBFC13;
public class SDKApp
{
private QBSessionManager sessionMgr;
public SDKApp()
{
// in the class constructor - sessionMgr is a member variable
sessionMgr = new QBSessionManager();
}
public void GetData()
{
// open connection and begin session before data fetch - intentionally skipped this code
// during data fetch
IMsgSetRequest msgset = sessionMgr.CreateMsgSetRequest("US", 13, 0);
ICustomerQuery customerQuery = msgset.AppendCustomerQueryRq();
IMsgSetResponse msgRes = sessionMgr.DoRequests(msgset);
IResponseList responseList = msgRes.ResponseList;
if (responseList.Count > 0)
{
IResponse response = responseList.GetAt(0);
ICustomerRetList customerList = response.Detail as ICustomerRetList;
for (int i = 0; i <= customerList.Count - 1; i++)
{
ICustomerRet qbCustomer = customerList.GetAt(i);
string displayName = qbCustomer.Name.GetValue();
string entityType = "Customer";
if (qbCustomer.ParentRef != null)
{
entityType = "Job of " + qbCustomer.ParentRef.FullName.GetValue();
}
Console.WriteLine(displayName + " " + entityType);
}
}
// end session and close connection after data fetch - intentionally skipped this code
}
}
Related
I'm trying to do a batch request using MS Graph .NET SDK as shown here: https://learn.microsoft.com/en-us/graph/sdks/batch-requests?tabs=csharp
The only problem is that when I run the code, nothing happens.
I'm trying to move a set of emails (stored in a list) to another mail folder.
Am I missing anything?
The move request is here https://learn.microsoft.com/en-us/graph/api/message-move?view=graph-rest-1.0&tabs=http
When used in a single query it works, but not when batching.
Below you will find the code, in this case I'm looping to 20 just to test as 20 is the maximum queries per batch.
Thanks in advance.
for (int i = 0; i < 20; i++)
{
var mail = invalidMessages[i];
var userRequest = client.Me.Messages[mail.Id]
.Move(failureFolderID)
.Request();
requestID = batchRequestContent.AddBatchRequestStep(userRequest);
}
var returnedResponse = await client.Batch.Request().PostAsync(batchRequestContent);
EDIT: I tried to change the method to POST
userRequest.Method = System.Net.Http.HttpMethod.Post;
but I get a ServiceException: 'Code: BadRequest
Message: Write request id : fe23b1c1-663d-4499-829a-291d04a12b48 does not contain Content-Type header or body.'
The Microsoft Graph message-move API call you are attempting to use is a POST request
The Microsoft Batch API handles POST requests differently than the other API methods.
As per https://learn.microsoft.com/en-us/graph/sdks/batch-requests?tabs=csharp
POST requests are handled a bit differently.
The SDK request builders generate GET requests, so
you must get the HttpRequestMessage and convert to a POST
To have a successful post with the batch API you need to
Create an HttpRequestMessage
provide a value for the HttpRequestMessage's Content property which houses the POST requests payload
So if I applied this to your code I would first create a class to represent the POST payload for the message-move API. As per https://learn.microsoft.com/en-us/graph/api/message-move?view=graph-rest-1.0&tabs=http
the POST API has one property called destinationId
destinationId - The destination folder ID, or a well-known folder name. For a list of supported well-known folder names, see mailFolder resource type.
public class MailMovePayload
{
public string destinationId { get; set; }
}
then I would use an instance of this class in this modified version of you code
string str = events.Content.ReadAsStringAsync().Result;
events.Method = HttpMethod.Post;
for (int i = 0; i < 20; i++)
{
var mail = invalidMessages[i];
//get the request message object from your request
var userRequestMessage = client.Me.Messages[mail.Id]
.Move(failureFolderID)
.GetHttpRequestMessage();
//set the message API method
userRequestMessage.Method = HttpMethod.Post;
//create the payload, I am assuming failureFolderID is
//the name of the folder where the mail will be moved to
var payloadData = new MailMovePayload { destinationId = failureFolderID };
//make the JSON payload for the request message
userRequestMessage.Content = new StringContent(JsonConvert.SerializeObject(payloadData), Encoding.UTF8, "application/json")
requestID = batchRequestContent.AddBatchRequestStep(userRequestMessage);
}
var returnedResponse = await client.Batch.Request().PostAsync(batchRequestContent);
return httpRequestMessage;
}
I have a VSTS project that uses Git for source control. The project has multiple repositories (11 to be precise) each with multiple branches.
Given a VSTS Id I am trying to get a list of all the Commits that are associated with that Id.
I am currently coding as follows
VSTSHelper helper = new VSTSHelper(); // my helper for establishing a connection
ProjectHttpClient projectClient = helper.Connection.GetClient<ProjectHttpClient>();
GitHttpClient gitClient = helper.Connection.GetClient<GitHttpClient>();
Microsoft.TeamFoundation.Core.WebApi.TeamProject project = projectClient.GetProject(helper.Project).Result;
List<GitRepository> gitRepositoryList = gitClient.GetRepositoriesAsync(project.Id).Result;
GitQueryCommitsCriteria criteria = new GitQueryCommitsCriteria()
{
IncludeWorkItems = true
};
foreach (GitRepository repo in gitRepositoryList)
{
List<GitBranchStats> branchStatsList = gitClient.GetBranchesAsync(repo.Id).Result;
foreach (GitBranchStats branchStats in branchStatsList)
{
criteria.ItemVersion = new GitVersionDescriptor() { Version = branchStats.Name, VersionType = GitVersionType.Branch };
List<GitCommitRef> commits = gitClient.GetCommitsAsync(repo.Id, criteria).Result;
if (commits.Count > 0)
{
List<GitCommitRef> commitsWithWorkItems = commits.Where(pc => pc.WorkItems.Count > 0).ToList();
if (commitsWithWorkItems.Count > 0)
{
// WorkItemIds is a list of int
List<GitCommitRef> workItemCommits = projectCommitsWithWorkItems.Where(
pc => pc.WorkItems.Any(x => this.WorkItemIds.Contains(Convert.ToInt32(x.Id)))).ToList();
// get the changes associated with the commit here
if (workItemCommits.Count > 0)
{
foreach (GitCommitRef wiCommit in workItemCommits)
{
GitCommitChanges wiChanges = gitClient.GetChangesAsync(wiCommit.CommitId, repo.Id).Result;
}
}
}
}
}
}
The work item id that is passed to my code (e.g Id = 810) has code that was originally committed against another Work Item Id (e.g. 675) in a different branch and then moved to the given Id. The code was then edited and then committed against the new Id (810)
My code above only ever finds the original commit against item 675 - and all the code changes are shown against this Id - including those that I was expecting to see against 810. Nothing is ever returned for Id 810.
Despite lots of googling I find myself struggling big time and I presume that I am misunderstanding some big time!
Any help or pointers in the right direction would be greatly appreciated.
You can use below code to get all the commits which link to a given work item:
As the REST API GET a work item with Fully expanded, all the links information exist under relations object. Then you can get the commits by filtering the url which contains vstfs:///Git/Commit.
int id = workitemID;
var token = "PAT";
String Uri = "https://account.visualstudio.com/DefaultCollection";
var Connection1 = new VssConnection(new Uri(Uri), new VssBasicCredential(string.Empty, token));
WorkItemTrackingHttpClient workItemTrackingClient = Connection1.GetClient<WorkItemTrackingHttpClient>();
WorkItem workitem = workItemTrackingClient.GetWorkItemAsync(id, expand: WorkItemExpand.All).Result;
Console.WriteLine("Related commits contain: ");
foreach (var relation in workitem.Relations)
{
if (relation.Url.Contains("vstfs:///Git/Commit"))
{
Console.WriteLine("commit: {0}", relation.Url);
}
}
To Get the commit sha-1 value (commit ID), it's located in the last 40 characters of the relation.Url which separate with repository ID by %2f. So the url format actually is vstfs:///Git/Commit/{projectID}%2f{repositoryID}%2f{commitID}.
Such as for a relation.Url as below:
vstfs:///Git/Commit/f7855e29-6f8d-429d-8c9b-41fd4d7e70a4%2fad3acf8e-b269-48e5-81bc-354251856b51%2fb802c91e68f321676fe31eca9dda048e7032ea11"
The commit sha-1 value is b802c91e68f321676fe31eca9dda048e7032ea11.
The repository ID is ad3acf8e-b269-48e5-81bc-354251856b51.
The project ID is f7855e29-6f8d-429d-8c9b-41fd4d7e70a4.
I have been working on a requirement, i.e. when a bug is created/inprogress in TFS post a HTTP call to Slack (third party collaboration tool).
When a bug is closed post one more HTTP call to Slack.
I had implemented TFS server side plugin, unfortunately we don't have complete access to TFS and cannot implement. So, planning to implement Webapi and host it (say in Docker container) and whenever bug created / closed event happens in TFS it should post HTTP call.
I have created a simple console app with a method and it's working fine.
any sample code or thoughts to convert it to web api?
if I host, can it monitor TFS events and posts some HTTP calls?
public class GetWI
{
static void Main(string[] args)
{
GetWI ex = new GetWI();
ex.GetWorkItemsByWiql();
}
public void GetWorkItemsByWiql()
{
string _personalAccessToken = "xxxx";
string _credentials = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", "", _personalAccessToken)));
//this is needed because we want to create a project scoped query
string project = "Agileportfolio";
//create wiql object
var wiql = new
{
query = "Select [State], [Title] " +
"From WorkItems " +
"Where [Work Item Type] = 'Bug' " +
"And [System.TeamProject] = '" + project + "' " +
"And [System.State] = 'New' " +
"Order By [State] Asc, [Changed Date] Desc"
};
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("https://test.visualstudio.com");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", _credentials);
//serialize the wiql object into a json string
var postValue = new StringContent(JsonConvert.SerializeObject(wiql), Encoding.UTF8, "application/json"); //mediaType needs to be application/json for a post call
var method = new HttpMethod("POST");
var httpRequestMessage = new HttpRequestMessage(method, "https://abrahamdhanyaraj.visualstudio.com/_apis/wit/wiql?api-version=2.2") { Content = postValue };
var httpResponseMessage = client.SendAsync(httpRequestMessage).Result;
if (httpResponseMessage.IsSuccessStatusCode)
{
WorkItemQueryResult workItemQueryResult = httpResponseMessage.Content.ReadAsAsync<WorkItemQueryResult>().Result;
//now that we have a bunch of work items, build a list of id's so we can get details
var builder = new System.Text.StringBuilder();
foreach (var item in workItemQueryResult.WorkItems)
{
builder.Append(item.Id.ToString()).Append(",");
}
//clean up string of id's
string ids = builder.ToString().TrimEnd(new char[] { ',' });
HttpResponseMessage getWorkItemsHttpResponse = client.GetAsync("_apis/wit/workitems?ids=" + ids + "&fields=System.Id,System.Title,System.State&asOf=" + workItemQueryResult.AsOf + "&api-version=2.2").Result;
if (getWorkItemsHttpResponse.IsSuccessStatusCode)
{
var result = getWorkItemsHttpResponse.Content.ReadAsStringAsync().Result;
//Read title
}
}
// Create Channel
string name = "xyzz3";
var payload = new
{
token = "xoxp-291239704800-292962676087-297314229698-a80e720d98e443c8afb0c4cb2c09e745",
name = "xyzz3",
};
var serializedPayload = JsonConvert.SerializeObject(payload);
var response = client.PostAsync("https://slack.com/api/channels.create" + "?token=test&name=" + name + "&pretty=1",
new StringContent(serializedPayload, Encoding.UTF8, "application/json")).Result;
if (response.IsSuccessStatusCode)
{
dynamic content = JsonConvert.DeserializeObject(
response.Content.ReadAsStringAsync()
.Result);
}
}
}
I use wcf service to listen events from TFS. You may find my project here: https://github.com/ashamrai/tfevents
For wcf service:
Update your ServiceName.svc file and add:
Factory="System.ServiceModel.Activation.WebServiceHostFactory"
Create web method to use json:
[OperationContract]
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)]
void WorkItemChangedEvent(Stream EventData);
Convert stream with Newtonsoft.Json to get information about event and work item:
StreamReader _reader = new StreamReader(pEventData, Encoding.UTF8);
string _eventStr = _reader.ReadToEnd();
WorkItemEventCore _wieventcorre = JsonConvert.DeserializeObject(_eventStr);
Then you have to create the subscription with url "http://host:port/service.svc/webmethod": https://learn.microsoft.com/en-us/vsts/service-hooks/services/webhooks
Instead of using a query and manually polling Visual Studio Team Services (VSTS), you can use a concept called WebHooks. You configure a WebHook in VSTS to listen for events and send these to a public endpoint. One event type is for Work Items. The endpoint can be any type of public endpoint, for example an Azure Function.
If the only thing you want to do is post the events to Slack, it's even easier because that's a standard integration point: Slack with VSTS.
This is much easier then using a server side plugin or writing your own Web API.
I know how to create a single entity in single request. However, one requirement wants me to create multiple entities (in my case it's multiple entries in ContactSet). I tried putting array to
POST /XRMServices/2011/OrganizationData.svc/ContactSet
[{
"MobilePhone": "+0012 555 555 555",
"YomiFullName" : "Demo User 1",
"GenderCode" : {
"Value" : 1
}
.....
<data removed for sanity>
.....
},
{
"MobilePhone": "+0012 555 555 111",
"YomiFullName" : "Demo User 2",
"GenderCode" : {
"Value" : 1
}
.....
<data removed for sanity>
.....
}]
However this does not work and I could not find any documentation explaining me ways to achieve this. Any help would be greatly appreciated.
You need to use an ExecuteMultipleRequest, I don't believe this is available in Rest service however, but is available in the SOAP service.
// Get a reference to the organization service.
using (_serviceProxy = new OrganizationServiceProxy(serverConfig.OrganizationUri, serverConfig.HomeRealmUri,serverConfig.Credentials, serverConfig.DeviceCredentials))
{
// Enable early-bound type support to add/update entity records required for this sample.
_serviceProxy.EnableProxyTypes();
#region Execute Multiple with Results
// Create an ExecuteMultipleRequest object.
requestWithResults = new ExecuteMultipleRequest()
{
// Assign settings that define execution behavior: continue on error, return responses.
Settings = new ExecuteMultipleSettings()
{
ContinueOnError = false,
ReturnResponses = true
},
// Create an empty organization request collection.
Requests = new OrganizationRequestCollection()
};
// Create several (local, in memory) entities in a collection.
EntityCollection input = GetCollectionOfEntitiesToCreate();
// Add a CreateRequest for each entity to the request collection.
foreach (var entity in input.Entities)
{
CreateRequest createRequest = new CreateRequest { Target = entity };
requestWithResults.Requests.Add(createRequest);
}
// Execute all the requests in the request collection using a single web method call.
ExecuteMultipleResponse responseWithResults =
(ExecuteMultipleResponse)_serviceProxy.Execute(requestWithResults);
// Display the results returned in the responses.
foreach (var responseItem in responseWithResults.Responses)
{
// A valid response.
if (responseItem.Response != null)
DisplayResponse(requestWithResults.Requests[responseItem.RequestIndex], responseItem.Response);
// An error has occurred.
else if (responseItem.Fault != null)
DisplayFault(requestWithResults.Requests[responseItem.RequestIndex],
responseItem.RequestIndex, responseItem.Fault);
}
}
ExecuteMultipleRequest is a good but not the only way. If you use CRM 2016 you can use Batch operations that is available in new WebApi. Check article that describes it - https://msdn.microsoft.com/en-us/library/mt607719.aspx
You can use a Web API action (see MSDN) to execute an ExecuteTransactionRequest, as described here. Subject of the example on MSDN is the WinOpportunityRequest, but it should work with any supported request, including custom actions.
I implemented conference call in Twilio, but it doesn't work. The error is:
Error: 11200 HTTP retrieval failure
In more details :
405 - HTTP verb used to access this page is not allowed.
Code:
string AccountSid = "...";
string AuthToken = ".....";
var twilio = new TwilioRestClient(AccountSid, AuthToken);
string appversion = twilio.ApiVersion;
ArrayList participants = new ArrayList();
// participants.Add("+972599223072");
participants.Add(txtphone1.Text);
participants.Add(txtphone2.Text);
participants.Add(txtphone3.Text);
participants.Add(txtphone4.Text);
participants.Add(txtphone5.Text);
participants.Add(txtphone6.Text);
participants.Add(txtphone7.Text);
// Go through the participants array and call each person.
foreach (string user in participants)
{
if (user != "")
{
var options = new CallOptions();
options.Url = "http://sandbox4.eureeca.com/Conference/conference.xml";
options.To = user;
options.From = "+97243741357";
options.Method = "POST";
options.Record = true;
// options.StatusCallback = "/2010-04-01/Accounts/" + AccountSid + "/Calls";
var call = twilio.InitiateOutboundCall(options);
Console.WriteLine(call.Sid);
}
Code END
Conference.xml content :
<?xml version="1.0" encoding="utf-8" ?>
<Response>
<Say>Joining a conference room</Say>
<Dial>
<Conference>MyConference</Conference>
</Dial>
</Response>
Twilio evangelist here.
Looks like you're TwiML is in a static XML file? Its pretty common for web servers to not allow POST requests to static files. You can either reconfigure your web server to allow this, or change the CallOptions Method property to `GET' to tell Twilio to make a GET request for the file rather than a POST.
Hope that helps.