Need to create a folder(and a file inside it) using C# inside Azure DevOps repository - be it Git or TFVC - c#

From Azure DevOps portal, I can manually add file/ folder into repository irrespective of the fact that source code is cloned or not - Image for illustration.
However, I want to programmatically create a folder and a file inside that folder within a Repository from c# code in my ASP .NET core application.
Is there a Azure DevOps service REST API or any other way to do that? I'll use BASIC authentication through PAT token only.
Note : I'm restricted to clone the source code at local repository.
Early reply is really appreciated.
I tried HttpClient, GitHttpClient and LibGit2Sharp but failed.

Follow below steps in your C# code
call GetRef REST https://dev.azure.com/{0}/{1}/_apis/git/repositories/{2}/refs{3}
this should return the object of your repository branch which you can use to push your changes
Next, call Push REST API to create folder or file into your repository
https://dev.azure.com/{0}/{1}/_apis/git/repositories/{2}/pushes{3}
var changes = new List<ChangeToAdd>();
//Add Files
//pnp_structure.yml
var jsonContent = File.ReadAllText(#"./static-files/somejsonfile.json");
ChangeToAdd changeJson = new ChangeToAdd()
{
changeType = "add",
item = new ItemBase() { path = string.Concat(path, "/[your-folder-name]/somejsonfile.json") },
newContent = new Newcontent()
{
contentType = "rawtext",
content = jsonContent
}
};
changes.Add(changeJson);
CommitToAdd commit = new CommitToAdd();
commit.comment = "commit from code";
commit.changes = changes.ToArray();
var content = new List<CommitToAdd>() { commit };
var request = new
{
refUpdates = refs,
commits = content
};
var personalaccesstoken = _configuration["azure-devOps-configuration-token"];
var authorization = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", "", personalaccesstoken)));
_logger.LogInformation($"[HTTP REQUEST] make a http call with uri: {uri} ");
//here I making http client call
// https://dev.azure.com/{orgnizationName}/{projectName}/_apis/git/repositories/{repositoryId}/pushes{?api-version}
var result = _httpClient.SendHttpWebRequest(uri, method, data, authorization);

Related

How can we add existing links in Azure DevOps programmatically

I want to link the existing work items which are already created in a project under Azure DevOps by writing a code or program in C#, so is there any kind of API or SDK which can be used to link the work items programmatically?
The Workitems can be of any type i.e.
Bug
User Story
Issue
Task etc.
The linking between the Workitems can also be of any type i.e. Relational, Parent-Child, etc.
Recently I referred to this link for my problem.
The link contains issue very much related and similar to mine, however it is not working as expected when I tried it.
Given:
//int relatedId = ...
//int id = ...
//CancellationToken token = ...
//string organization = ...
//string projectName = ...
//WorkItemTrackingHttpClient azureClient = ...
Create a JsonPatchDocument as below:
JsonPatchDocument patchDoc = new JsonPatchDocument();
patchDoc.Add(
new JsonPatchOperation
{
From = null,
Operation = Operation.Add,
Path = "/relations/-",
Value = new {
rel = "System.LinkTypes.Related",
url = $"https://dev.azure.com/{organization}/{projectName}/_workitems/edit/{relatedId}",
attributes = new
{
comment = $"Created programmatically on {DateTime.Now}."
}
}
}
);
and call this async method of Azure DevOps SDK:
await azureClient.UpdateWorkItemAsync(patchDoc, id, false, true, true, WorkItemExpand.All, cancellationToken: token);
In the case above we created a related link using System.LinkTypes.Related referenceName.
For a full link types reference guide in Azure DevOps refer to this so's question or this microsoft's doc.

How to access Box folder shared with me using C# SDK

Someone has shared a Box.com folder with me using the link. I need to be able to use the C# SDK or REST API to download the documents from their folder.
I have tried all 3 authentication types and have attempted to access with both the C# SDK and REST API.
//SDK attempt
var findFolder = await client.SharedItemsManager.SharedItemsAsync("https://<userWhoSharedWithMe>.box.com/s/<folderHash>"); // notFound
var folder = await client.FoldersManager.GetInformationAsync(findFolder.Id);
var items = folder.ItemCollection;
//API Attempt
var client = new HttpClient
{
BaseAddress = new Uri("https://api.box.com")
};
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "<bearerToken>");
var response = await client.GetAsync("2.0/folders/<folderId>/items");
var content = await response.Content.ReadAsStringAsync();
Is there any way to programmatically download documents from a box folder that was shared with me via link?
-- Edited 06/04/2019
The folder owner and I have tried various things and it seems the API still will not allow me to see the content of the shared folder. Is there anything the folder owner needs to do to make it visible?
Based on the suggestion that I received from a Box employee, I made the following changes.
First the snippet that didn't work as expected:
// DOES NOT WORK
var reader = new StreamReader("box-config.json");
var json = reader.ReadToEnd();
var config = BoxConfig.CreateFromJsonString(json);
var sdk = new BoxJWTAuth(config);
var token = sdk.AdminToken();
var session = new OAuthSession(token, "N/A", 3600, "bearer");
boxClient = new BoxClient(config, session, asUser: boxUserId);
Secondly, the modified version that worked, allowing me to see the folder that was shared to me and allowed me to traverse its contents:
// THIS WORKS !!!!!!!!
var reader = new StreamReader("box-config.json");
var json = reader.ReadToEnd();
var config = BoxConfig.CreateFromJsonString(json);
var sdk = new BoxJWTAuth(config);
var token = sdk.UserToken(boxUserId);
boxClient = sdk.UserClient(token, boxUserId);
And for completeness' sake, here's a snippet of code that will allow you to programmatically access a Box folder and traverse its contents:
//folderId <-- You can find this ID by logging into your box account and navigating to the folder that you're interested in accessing programmatically.
var items = await boxClient.FoldersManager.GetFolderItemsAsync(folderId, limit: 5000, offset: 0, autoPaginate: false,
sort: "name", direction: BoxSortDirection.DESC);
// How many things are this folder?
Console.WriteLine($"TotalCount: {items.TotalCount}");
// Loop through those items
foreach (var item in items.Entries)
{
// Get info on each item
var file = await boxClient.FilesManager.GetInformationAsync(item.Id);
// Print the filename
Console.WriteLine($"file: {item.Name}");
}

Connect CouchDB with asp.net C# application

How to connect couchDB with ASP.NET C# application? If any one can you give a sample application.
I had the same need and after evaluating the options available, to meet the requirements of my application, I created any components that helped me a lot and maybe they can help you and also others. I make it clear that I have no intention of promoting myself here, just sharing something that may be useful.
The detailed explanation of how to configure and use it is on Github.
Link: Nuget Package |
Github
Example of use for retrieving documents with mango-querie:
IList<User> users;
var sts = new List<String> { "ACTIVE", "LOCKED" };
using (UserRepository db = new UserRepository())
{
var query = db.FindOf("list-status", new { id = "OwnerIdloop.user.7", statuses = sts });
users = db.List<User>(query);
}
Array.ForEach(users.ToArray(), Console.WriteLine);
Example of adding documents:
User user = createUser("email#email.com");
using (UserRepository db = new UserRepository())
{
var result = db.Insert<User>(user); // add document and return instance changed with operation revision id
Console.WriteLine(result.Revision);
}
Example of changing documents:
using (UserRepository db = new UserRepository())
{
// Load document data by ID
var user = db.Get<User>("email#email.com");
user.Name = user.Name + "::CHANGED";
var result = db.Update<User>(user); // update document and return instance changed with operation revision id
Console.WriteLine(result.Revision);
}
Example of deleting documents:
using (UserRepository db = new UserRepository())
{
// Load document data by ID
var user = db.Get<User>("email#email.com");
var result = db.Delete<User>(user); // delete document from database. Return true case sucess or false case not deleted
Console.WriteLine($"Sucesso: {result}");
}
After installing the NuGet, just create an instance of MyCouch.Client and pass it the URL of your database.
using (var client = new MyCouchClient("http://127.0.0.1:5984/test"))
{
//Consume here
}
The format is: {scheme}://[{username}:{password}]/{authority}/{localpath}. From v0.11.0, there's a specific MyCouchUriBuilder that you can use for building the Uri. It will automatically e.g. apply Uri.EscapeDataString to username and password when calling SetBasicCredentials.
var uriBuilder = new MyCouchUriBuilder("http://localhost:5984/")
.SetDbName(TestConstants.TestDbName)
.SetBasicCredentials("foob#r", "p#ssword");
return new MyCouchClient(uriBuilder.Build());
For more details Click Here

Using tuespechkin with MVC project in Azure

I can't manage to get pechkin or tuespechkin to work on my azure site.
Whenever I try to access the site it just hangs with no error message (even with customErrors off). Is there any further setup I'm missing? Everything works perfectly locally.
For a 64 bit app I'm completing the following steps:
Create a new Empty MVC App with Azure, make sure Host in the cloud is selected
Change the app to 64 bit
Log onto the azure portal and upgrade the app to basic hosting and change it to 64 bit
Install the TuesPechkin.Wkhtmltox.Win64 and TuesPechkin nuget packages
Add a singleton class to return the IConverter
public class TuesPechkinConverter
{
private static IConverter converter;
public static IConverter Converter
{
get
{
if (converter == null)
{
converter =
new ThreadSafeConverter(
new PdfToolset(
new Win64EmbeddedDeployment(
new TempFolderDeployment())));
}
return converter;
}
}
}
Add a Home controller with the following code in the Index Action:
var document = new HtmlToPdfDocument
{
GlobalSettings =
{
ProduceOutline = true,
DocumentTitle = "Pretty Websites",
PaperSize = PaperKind.A4, // Implicit conversion to PechkinPaperSize
Margins =
{
All = 1.375,
Unit = Unit.Centimeters
}
},
Objects =
{
new ObjectSettings { HtmlText = "<h1>Pretty Websites</h1><p>This might take a bit to convert!</p>" },
new ObjectSettings { PageUrl = "www.google.com" }
}
};
byte[] pdfBuf = TuesPechkinConverter.Converter.Convert(document);
return File(pdfBuf, "application/pdf", "DownloadName.pdf");
As far as i know, you can't make it work in a web app. However, there is a way you can do it: you have to create a cloud service and add a worker role to it. TuesPechkin will be installed in this worker role.
The workflow would be the following: from your cloud web app, you would access the worker role(this thing is possible by configuring the worker role to host Asp.NET Web API 2). The worker role would configure a converter using TuesPechkin and would generate the PDF. We would wrap the pdf in the web api response and send it back. Now, let's do it...
To add a cloud service (suppose you have Azure SDK installed), go to Visual Studio -> right click your solution -> Add new project -> select Cloud node -> Azure Cloud Service -> after you click OK select Worker Role and click OK.
Your cloud service and your worker role are created. Next thing to do is to configure your Worker Role so it can host ASP.NET Web API 2.
This configuration is pretty straightforward, by following this tutorial.
After you have configured your Worker Role to host a web api, you will have to install the TuesPechkin.Wkhtmltox.Win64 and TuesPechkin nuget packages.
Your configuration should now be ready. Now create a controller, in which we will generate the PDF: add a new class in your Worker Role which will extend ApiController:
public class PdfController : ApiController
{
}
Add an action to our controller, which will return an HttpResponseMessage object.
[HttpPost]
public HttpResponseMessage GeneratePDF(PdfViewModel viewModel)
{
}
Here we will configure two ObjectSettings and GlobalSettings objects which will be applied to an HtmlToPdfDocument object.
You now have two options.
You can generate the pdf from html text(maybe you sent the html of your page in the request) or directly by page url.
var document = new HtmlToPdfDocument
{
GlobalSettings =
{
ProduceOutline = true,
DocumentTitle = "Pretty Websites",
PaperSize = PaperKind.A4, // Implicit conversion to PechkinPaperSize
Margins =
{
All = 1.375,
Unit = Unit.Centimeters
}
},
Objects = {
new ObjectSettings { HtmlText = "<h1>Pretty Websites</h1><p>This might take a bit to convert!</p>" },
new ObjectSettings { PageUrl = "www.google.com" }
}
};
A nice thing to now is that when using page url, you can use the ObjectSettings object to post parameters:
var obj = new ObjectSettings();
obj.LoadSettings.PostItems.Add
(
new PostItem()
{
Name = "paramName",
Value = paramValue
}
);
Also, from TuesPechkin documentation the converter should be thread safe and should be kept somewhere static, or as a singleton instance:
IConverter converter =
new ThreadSafeConverter(
new RemotingToolset<PdfToolset>(
new Win64EmbeddedDeployment(
new TempFolderDeployment())));
Finally you wrap the pdf in the response content, set the response content type to application/pdf and add the content-disposition header and that's it:
byte[] result = converter.Convert(document);
MemoryStream ms = new MemoryStream(result);
response.StatusCode = HttpStatusCode.OK;
response.Content = new StreamContent(ms);
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/pdf");
response.Content.Headers.Add("content-disposition", "attachment;filename=myFile.pdf");
return response;
I'm afraid the answer is that it's not possible to get wkhtmltopdf working on Azure.
See this thread.
I am assuming you mean running wkhtmltopdf on Windows Azure Websites.
wkhtmltopdf uses Window's GDI APIs which currently don't work on Azure
Websites.
Tuespechkin supported usage
It supports .NET 2.0+, 32 and 64-bit processes, and IIS-hosted applications.
Azure Websites does not currently support the use of wkhtmltopdf.
Workaround
I ended up creating a Azure Cloud Service, that runs wkhtmltopdf.exe. I send the html to the service, and get a byte[] in return.

How to configure CORS setting for Blob storage in windows azure

I have created several containers in a azure storage and also uploaded some files into these containers. Now I need to give domain level access to the container/blobs. So I tried it from code level like below.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
CloudConfigurationManager.GetSetting("StorageConnectionString"));
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
ServiceProperties blobServiceProperties = new ServiceProperties();
blobServiceProperties.Cors.CorsRules.Add(new CorsRule(){
AllowedHeaders = new List<string>() {"*"},
ExposedHeaders = new List<string>() {"*"},
AllowedMethods = CorsHttpMethods.Post | CorsHttpMethods.Put | CorsHttpMethods.Get | CorsHttpMethods.Delete ,
AllowedOrigins = new List<string>() { "http://localhost:8080/"},
MaxAgeInSeconds = 3600,
});
blobClient.SetServiceProperties(GetBlobServiceProperties());
But above code seems to be work if I am creating everything from code (Correct me if I am wrong). I also find setting like below Here,
<CorsRule>
<AllowedOrigins>http://www.contoso.com, http://www.fabrikam.com</AllowedOrigins>
<AllowedMethods>PUT,GET</AllowedMethods>
<AllowedHeaders>x-ms-meta-data*,x-ms-meta-target,x-ms-meta-source</AllowedHeaders>
<ExposedHeaders>x-ms-meta-*</ExposedHeaders>
<MaxAgeInSeconds>200</MaxAgeInSeconds>
</CorsRule>
But I didn't get where this code have to put. I mean in which file. Or is there any setting for CORS while creating container or blob from azure portal. Please assist. Any help would be appreciable. Thanks!
The following answers the question that was actually asked in the title. It appears the questioner already knew how to do this largely from his code, but here is my answer to this. Unfortunately the code samples MS has put out has been far from easy or clear, so I hope this helps someone else. In this solution all you need is a CloudStorageAccount instance, which you can call this function from then (as an extension method).
// USAGE:
// -- example usage (in this case adding a wildcard CORS rule to this account --
CloudStorageAccount acc = getYourStorageAccount();
acc.SetCORSPropertiesOnBlobService(cors => {
var wildcardRule = new CorsRule() { AllowedMethods = CorsHttpMethods.Get, AllowedOrigins = { "*" } };
cors.CorsRules.Add(wildcardRule);
return cors;
});
// CODE:
/// <summary>
/// Allows caller to replace or alter the current CorsProperties on a given CloudStorageAccount.
/// </summary>
/// <param name="storageAccount">Storage account.</param>
/// <param name="alterCorsRules">The returned value will replace the
/// current ServiceProperties.Cors (ServiceProperties) value. </param>
public static void SetCORSPropertiesOnBlobService(this CloudStorageAccount storageAccount,
Func<CorsProperties, CorsProperties> alterCorsRules)
{
if (storageAccount == null || alterCorsRules == null) throw new ArgumentNullException();
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
ServiceProperties serviceProperties = blobClient.GetServiceProperties();
serviceProperties.Cors = alterCorsRules(serviceProperties.Cors) ?? new CorsProperties();
blobClient.SetServiceProperties(serviceProperties);
}
It may be helpful to consider the properties of the CorsRule class:
CorsRule corsRule = new CorsRule() {
AllowedMethods = CorsHttpMethods.Get, // Gets or sets the HTTP methods permitted to execute for this origin
AllowedOrigins = { "*" }, // (IList<string>) Gets or sets domain names allowed via CORS.
//AllowedHeaders = { "*" }, // (IList<string>) Gets or sets headers allowed to be part of the CORS request
//ExposedHeaders = null, // (IList<string>) Gets or sets response headers that should be exposed to client via CORS
//MaxAgeInSeconds = 33333 // Gets or sets the length of time in seconds that a preflight response should be cached by browser
};
Let me try to answer your question. As you know, Azure Storage offers a REST API for managing storage contents. An operation there is Set Blob Service Properties and one of the things you do there is manage CORS rules for blob service. The XML you have included in the question is the request payload for this operation. The C# code you mentioned is actually storage client library which is essentially a wrapper over this REST API written in .Net. So when you use the code above, it actually invokes the REST API and sends the XML.
Now coming to options on setting up CORS rules, there're a few ways you can achieve that. If you're interested in setting them up programmatically, then you can either write some code which consumes the REST API or you could directly use .Net storage client library as you have done above. You could simply create a console application, put the code in there and execute that to set the CORS rule. If you're looking for some tools to do that, then you can try one of the following tools:
Azure Management Studio from Cerebrata: http://www.cerebrata.com
Cloud Portam: http://www.cloudportam.com (Disclosure: This product is built by me).
Azure Storage Explorer (version 6.0): https://azurestorageexplorer.codeplex.com/
Its not a good idea to give domain level access to your containers. You can make the container private, upload the files (create blob) and then share it by using Shared Access Policy.
The below code can help you.
static void Main(string[] args)
{
var account = CloudStorageAccount.Parse(ConfigurationManager.ConnectionStrings["AzureStorageAccount"].ConnectionString);
var bClient = account.CreateCloudBlobClient();
var container = bClient.GetContainerReference("test-share-container-1");
container.CreateIfNotExists();
// clear all existing policy
ClearPolicy(container);
string newPolicy = "blobsharepolicy";
CreateSharedAccessPolicyForBlob(container, newPolicy);
var bUri = BlobUriWithNewPolicy(container, newPolicy);
Console.ReadLine();
}
static void ClearPolicy(CloudBlobContainer container)
{
var perms = container.GetPermissions();
perms.SharedAccessPolicies.Clear();
container.SetPermissions(perms);
}
static string BlobUriWithNewPolicy(CloudBlobContainer container, string policyName)
{
var blob = container.GetBlockBlobReference("testfile1.txt");
string blobContent = "Hello there !!";
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(blobContent));
ms.Position = 0;
using (ms)
{
blob.UploadFromStream(ms);
}
return blob.Uri + blob.GetSharedAccessSignature(null, policyName);
}
static void CreateSharedAccessPolicyForBlob(CloudBlobContainer container, string policyName)
{
SharedAccessBlobPolicy sharedPolicy = new SharedAccessBlobPolicy()
{
SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24),
Permissions = SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Read
};
var permissions = container.GetPermissions();
permissions.SharedAccessPolicies.Add(policyName, sharedPolicy);
container.SetPermissions(permissions);
}
<connectionStrings>
<add name="AzureStorageAccount" connectionString="DefaultEndpointsProtocol=https;AccountName=[name];AccountKey=[key]" />
</connectionStrings>

Categories

Resources