TFS Integration - c#

I am trying to do a TFS integration with automatic sync with tfs to my db..
All I m doing with window service...
For that I have coded as below...
DataRow dr = dstSyncWorkItem.Tables["Workitems"].Rows[i];
String uri = ConfigurationManager.AppSettings["TfsUri"] + dr["ProCollectionName"];
Uri collectionUri = new Uri(uri);
NetworkCredential myNetCredentials = new NetworkCredential(ConfigurationManager.AppSettings["TfsUsername"], ConfigurationManager.AppSettings["TfsPassword"]);
ICredentials myCredentials = (ICredentials)myNetCredentials;
TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(collectionUri, myCredentials);
WorkItemStore workItemStore = tpc.GetService<WorkItemStore>();
Project teamProject = workItemStore.Projects[dr["Project"].ToString()];
WorkItemType workItemType = teamProject.WorkItemTypes[dr["Type"].ToString()];
WorkItem workItem = new WorkItem(workItemType);
workItem.Title = dr["Title"].ToString();
workItem.Description = dr["Desc"].ToString();
workItem.Save();
and This will giving following error...
TF237124: Work Item is not ready to save.

You need to validate the work item before you can save it. Call:
ArrayList validation = workItem.Validate();
This will ensure that any changes you've made are appropriate, and make any additional state changes that your work item rules have defined based on your changes.
If there are validation failures, you must deal with them appropriately. Otherwise, you can then call:
workItem.Save();

You have not filled out all of the required fields. While calling the Validate() function will give you a list of errors you will be required to fill out Area & Iteration paths. Along with Title these are the only OOB required fields.
You don't see this in any of the UI's as they are populated by default. If you fill them out with something like "Iteration/myproject/" you should pass.

Related

How to Get TFS WorkItem URL depending on WorkItem ID

i could successfully add bugs into TFS programmatically,
var tfsURI = new Uri("http://test:8080/tfs");
var networkCredential1 = new NetworkCredential("test", "test!");
ICredentials credential = (ICredentials)networkCredential1;
Microsoft.VisualStudio.Services.Common.WindowsCredential winCred = new Microsoft.VisualStudio.Services.Common.WindowsCredential(credential);
VssCredentials vssCredentials = new VssCredentials(winCred);
using (TfsTeamProjectCollection collection = new TfsTeamProjectCollection(tfsURI, vssCredentials))
{
collection.EnsureAuthenticated();
WorkItemStore workItemStore = collection.GetService<WorkItemStore>();
Project teamProject = workItemStore.Projects["Test"];
WorkItemType workItemType = teamProject.WorkItemTypes["Bug"];
WorkItem Defect = new WorkItem(workItemType);
FileInfo fi = new FileInfo(#"C:\\Document.docx");
Attachment tfsAttachment = new Attachment(fi.FullName);
Defect.Attachments.Add(tfsAttachment);
Defect.Title = "Testing from VS to TFS Bug";
Defect.Description = "Testing from VS to entered Bug in to TFS.";
Defect.Fields["Assigned To"].Value = "Test";
Defect.Save();
}
I have Newly Created WorkItem ID. Defect.ID provides me workitemID.
How can i get the URL of newly created WOrkItem by passing ID.
Let Me know if any API available? i need HTML Link of Newly created WorkItem so that anyone when click on URL, created WorkItem will be Open.
You could use Rest API to directly return a single work item
GET https://dev.azure.com/{organization}/{project}/_apis/wit/workitems/{id}?api-version=5.1
However this will only get a url to the json data for the bug created, not the URL of the HTML page of the bug. Such as below output that I got
https://tfsurl:8080/_apis/wit/workItems/workitemID
When I load the above link in browser, I got JSON data, instead of the HTML page for the work item I created.
Guess you want to fetch the url of HTML in web portal.
https://tfsurl:8080/tfs/DefaultCollection/PatrickProject/_workitems/edit/172/
In my case it was this and here DefaultCollection is the collection name and the PatrickProject is the project name. I used this url and got rid of the id '172' in this case and use the ID of newly created work item. This would return the URL to go to the work item HTML page.
So it's a fixed format, if you have Newly Created WorkItem ID and collection name , project name, you just need to follow above format and change the last value of work item ID. That's it , ignore of which work item type you created.
Hope this Helps!
I found solution after lots of research, may help to someone in future:
var tfsURI = new Uri("http://test:8080/tfs");
var networkCredential1 = new NetworkCredential("test", "test!");
ICredentials credential = (ICredentials)networkCredential1;
Microsoft.VisualStudio.Services.Common.WindowsCredential winCred = new Microsoft.VisualStudio.Services.Common.WindowsCredential(credential);
VssCredentials vssCredentials = new VssCredentials(winCred);
using (TfsTeamProjectCollection collection = new TfsTeamProjectCollection(tfsURI, vssCredentials))
{
collection.EnsureAuthenticated();
TswaClientHyperlinkService hyperlinkService =
collection.GetService<TswaClientHyperlinkService>();
String TFSurl = hyperlinkService.GetWorkItemEditorUrl(17648).ToString(); //17648 WorkItem ID
}

How to get project info based on owner name

I am using REST API C# to develop a tool. I would like to get project info based on owner name.
Does anyone have some sample code on how it should works?
Below is my code but it's not working.
Request ProjRequest = new Request("Projects");
ProjRequest.Workspace = "/workspace/xxx";
ProjRequest.Fetch = new List<string>()
{"Name"};
ProjRequest.Query = new Query("Owner.UserName", Query.Operator.Equals, "user name");
ProjResult result = restApi.Query(ProjRequest);
That looks pretty close. I think you just need to change the type to be singular:
Request ProjRequest = new Request("Project");
If that is still not working, inspect the Errors collection on the response and see what's wrong...

NetSuite SuiteTalk TransactionSearchAdvanced: recordList equals null

I have a small C# console application who's sole purpose is to receive records from a "Saved Search" in NetSuite(via SuiteTalk). I've been able to successfully connect and receive records from NetSuite for my Saved Search(the search runs fine through the web interface too), however when I attempt to access the results of the "Saved Search" through my application, I am unable to view them because the search object that is returned does not contain any data in the "recordList" property:
//Connect
var dataCenterAwareNetSuiteService = new DataCenterAwareNetSuiteService("XXXXXX");
dataCenterAwareNetSuiteService.Timeout = 1000 * 60 * 60 * 2;
//Adds Credentials etc...
dataCenterAwareNetSuiteService.tokenPassport = createTokenPassport();
//Setup Preferences
var prefs = new Preferences();
prefs.warningAsErrorSpecified = true;
prefs.warningAsError = false;
dataCenterAwareNetSuiteService.preferences = prefs;
var searchPrefs = new SearchPreferences();
dataCenterAwareNetSuiteService.searchPreferences = searchPrefs;
dataCenterAwareNetSuiteService.searchPreferences.pageSize = 5;
dataCenterAwareNetSuiteService.searchPreferences.pageSizeSpecified = true;
dataCenterAwareNetSuiteService.searchPreferences.bodyFieldsOnly = false;
dataCenterAwareNetSuiteService.searchPreferences.returnSearchColumns = false;
//Search
var tranSearchAdv = new TransactionSearchAdvanced();
var tranSearchRow = new TransactionSearchRow();
var tranSearchRowBasic = new TransactionSearchRowBasic();
tranSearchAdv.savedSearchId = "XXXX";
tranSearchRowBasic.internalId =
new SearchColumnSelectField[] { new SearchColumnSelectField() };
tranSearchRowBasic.tranId =
new SearchColumnStringField[] { new SearchColumnStringField() };
tranSearchRowBasic.dateCreated =
new SearchColumnDateField[] { new SearchColumnDateField() };
tranSearchRowBasic.total =
new SearchColumnDoubleField[] { new SearchColumnDoubleField() };
tranSearchRowBasic.entity =
new SearchColumnSelectField[] { new SearchColumnSelectField() };
tranSearchRow.basic = tranSearchRowBasic;
tranSearchAdv.columns = tranSearchRow;
//No errors,
//this works correctly and returns the "Saved Search" with the correct "totalRecords"
//but results.recordList == null while results.totalRecords = 10000000+
var results = dataCenterAwareNetSuiteService.search(tranSearchAdv);
I appears to me that the "recordList" object is the principal way data is retrieved from the results of a search(Related Java Example, Another Here). This is also the way the example API does it.
I have run this on multiple "Saved Search's" with the same results. I don't understand how you can have more than one record in "totalRecords" and yet the "recordList" remains null? Is there some configuration option that has to be set to allow me to access this property. Or maybe it's a security thing, the API user I have setup should have full access, is there anything else that need to be granted access?
NetSuite SuiteTalk is not well documented, and most of the examples online are not in C#, and not dealing with the issues that I'm experiencing. These factors make it very difficult to determine why the previously mentioned behavior is occurring, or even, to discover any alternative methods for retrieving the resulting data from the source "Saved Search".
Does anyone have any insight into this behavior? Is this the correct method of retrieving results from SuiteTalk? Is there any configuration from the API or Web Side that needs to be changed?
Update 1
I've also tried using the alternative way of getting result data by accessing the "searchRowList" object from the "SearchResult" object(suggested by #AdolfoGarza) However it returns mostly empty fields(null) similar to the "recordList" property I do not see a way to retrieve "Saved Search" data from this method.
Try getting the results with results.searchRowList.searchRow , thats how it works in php.
I was able to resolve the issue by removing this line in the code:
tranSearchRow.basic = tranSearchRowBasic;
Then like #AdolfoGarza reccomended, retrieving the results from "basic" field in "results.searchRowList"
For some reason the template API that I was using was setting up a "TransactionSearchAdvanced" referencing a blank "TransactionSearchBasic" record, not sure why but this was causing the results from "searchRowList" to be null. After removing it I now get non-null values in the proper fields.
As for "recordList", it's still null, not sure why, but as I have my data I don't think I'll continue to dig into this.

How do I programatically change the status of a test in VersionOne?

I am posting this because it might help someone using the VersionOne API SDK Client. I wanted to change the status of a test programmatically, to one of the following categories: Ready, InTesting, Passed, or Failed. I originally tried to change the attribute 'Status.Name' however I would get an error that the attribute is a Read-Only attribute. Another suggestion was to create a new attribute with the same name and that the new attribute would override the previous read-only attribute with the same name. However, it appears that I was looking at it backwards.
internal void TestStatusPassed(string str_TestID)
{
var testId = Oid.FromToken(str_TestID, _context.MetaModel);
var query = new Query(testId);
var testType = _context.MetaModel.GetAssetType("Test");
var sourceAttribute = testType.GetAttributeDefinition("Status.Name");
query.Selection.Add(sourceAttribute);
var result = _context.Services.Retrieve(query);
var test = result.Assets[0];
var oldSource = GetValue(test.GetAttribute(sourceAttribute).Value);
test.SetAttributeValue(sourceAttribute, "Passed");
_context.Services.Save(test);
}
This code will throw an exception "Cannot change a read-only attribute"...
I pulled the XML data for one test from the VersionOne Rest API and noticed a relation named "TestStatus" and then it had a number '9123' assigned to it. So I moved that test manually to 'In Testing' and the "TestStatus" changed to '9121'. Then I moved it to failed and the "TestStatus" changed to '155'. I repeated this with several tests from different testsets and noticed that the numbers for each status were consistent and then changed the code slightly and then I was able to programmatically change the status of each test. I changed "Status.Name" to "Status" and "Passed" to "TestStatus:9123" and now it moves the test into the passed category programmatically.
internal void TestStatusPassed(string str_TestID)
{
var testId = Oid.FromToken(str_TestID, _context.MetaModel);
var query = new Query(testId);
var testType = _context.MetaModel.GetAssetType("Test");
var sourceAttribute = testType.GetAttributeDefinition("Status");
query.Selection.Add(sourceAttribute);
var result = _context.Services.Retrieve(query);
var test = result.Assets[0];
var oldSource = GetValue(test.GetAttribute(sourceAttribute).Value);
test.SetAttributeValue(sourceAttribute, "TestStatus:9123");
_context.Services.Save(test);
}

NHIbernate & Rhino-Security does not save unless I call session.Flush()

I am having an issue using nHibernate and Rhino.Security. After struggling for hours to get the right config setup, I finally got the code to run without any errors. However, no entries are being saved to the database unless I call session.Flush().
Looking at various examples on the net; I should not have to call flush.
Here’s my config code:
var cfg = new Configuration()
.SetProperty(Environment.ConnectionDriver, typeof(SqlClientDriver).AssemblyQualifiedName)
.SetProperty(Environment.Dialect, typeof(MsSql2008Dialect).AssemblyQualifiedName)
.SetProperty(Environment.ConnectionString, "………")
.SetProperty(Environment.ProxyFactoryFactoryClass, typeof(ProxyFactoryFactory).AssemblyQualifiedName)
.SetProperty(Environment.ReleaseConnections, "on_close")
.SetProperty(Environment.UseSecondLevelCache, "true")
.SetProperty(Environment.UseQueryCache, "true")
.SetProperty(Environment.CacheProvider, typeof(HashtableCacheProvider).AssemblyQualifiedName)
.AddAssembly("GA.CAP.Website")
;
Security.Configure<AspNetUser>(cfg, SecurityTableStructure.Prefix);
var factory = cfg.BuildSessionFactory();
var session = factory.OpenSession();
var authorizationRepository = new AuthorizationRepository(session);
IoC.Container.RegisterInstance<IAuthorizationRepository>(authorizationRepository);
var permissionBuilderService = new PermissionsBuilderService(session, authorizationRepository);
IoC.Container.RegisterInstance<IPermissionsBuilderService>(permissionBuilderService);
var permissionService = new PermissionsService(authorizationRepository, session);
IoC.Container.RegisterInstance<IPermissionsService>(permissionService);
var authService = new AuthorizationService(permissionService, authorizationRepository);
IoC.Container.RegisterInstance<IAuthorizationService>(authService);
Test code:
authorizationRepository.CreateUsersGroup("GAAdmins");
var group = authorizationRepository.GetUsersGroupByName("GAAdmins");
The GetUsersGroupByName call returns null. If I add a session.Flush call in between the two calls, it works fine and returns the group.
Based on examples in various blogs, such as this one, I should not have to call flush. In addition, the test cases included with the Rhino.Security code do not do any flushing as shown here:
This is straight out of Rhino.Security's test case fixture:
// on first deploy
Operation operation = authorizationRepository.CreateOperation("/Account/View");
// when creating account
UsersGroup group = authorizationRepository.CreateUsersGroup("Belongs to " + account.Name);
// setting permission so only associated users can view
permissionsBuilderService
.Allow(operation)
.For(group)
.On(account)
.DefaultLevel()
.Save();
// when adding user to account
authorizationRepository.AssociateUserWith(user, group);
bool allowed = authorizationService.IsAllowed(user, account, "/Account/View");
Assert.True(allowed);
Is there some setting I am missing somewhere?
Thanks,
Rick
That is expected, RS uses the same session as your code, and calling Flush internally may result in unintended consequences.
Commit your transaction or call Flush

Categories