Create PortalItem with zip file

512
3
Jump to solution
10-19-2022 08:01 AM
JoeHershman
MVP Regular Contributor

We are trying to upload zip files to AGOL.  If I was doing in AGOL I would create the item, define it as a Code Sample (which will allow a generic zip file).

Hoped we could do this in Runtime (100.15).  I see this old thread How to create a new FeatureService PortalItem which seems to indicate only saving Maps is supported, but it is 3 years old so would hope that is no longer the case.

Seems pretty simple:

 

ZipFile.CreateFromDirectory(projectItem.MapPackagePath, outputfile);
var portalItem = new PortalItem(portal, PortalItemType.CodeSample, projectItem.Title);

using ( var fileStream = File.OpenRead(outputfile) )
{
	await portalItem.UpdateDataAsync(fileStream);
}

await portal.User.AddPortalItemAsync(portalItem);
await portalItem.ShareWithGroupsAsync(new[] { group });

 

Couple problems occur.

  • It requires that the user re-enter credentials on the call to new PortalItem even though authenticated
  • The primary issue: it never returns from the await portalItem.UpdateDataAsync.  It just hangs and so cannot ever put the item in AGOL

Is what I need to do supported?  If so what would be a correct way to do this

Thanks - Joe

Thanks,
-Joe
0 Kudos
1 Solution

Accepted Solutions
JoeHershman
MVP Regular Contributor

Never found a way to get anything to work with the Runtime API, but was able to do using the rest endpoint directly.

 

string zipfileName = CreateProjectZipfile(projectItem);

/* Does not seem that Runtime API handles creating a zip file item, so using rest API directly
/*    https://developers.arcgis.com/rest/users-groups-and-items/add-item.htm */

string url = $"https://www.arcgis.com/sharing/rest/content/users/{portal.User?.UserName}/additem";

using ( var formContent = new MultipartFormDataContent() )
{
	AddStringContent(formContent, projectItem);
	AddFileContent(formContent, zipfileName, projectItem);

	using ( HttpClient client = new HttpClient(new ArcGISHttpClientHandler()) )
	{
		var response = await client.PostAsync(url, formContent);
		var json = await response.Content.ReadAsStringAsync();

		await ShareItemWithGroupAsync(json);
	}
}


private void AddStringContent(MultipartFormDataContent formContent, ProjectItem projectItem)
{
	Dictionary<string, string> parameters = new Dictionary<string, string>()
	{
		{ "multipart", "false" },
		{ "title", projectItem.Title },
		{ "type", "Code Sample" },
		{ "async", "false" },
		{ "f", "json" }
	};

	//  For MultipartFormDataContent paramaters needs to be added as individual StringContent objects.  FormUrlEncodedContent does not work.
	foreach (var keyValuePair in parameters)
	{
		formContent.Add(new StringContent(keyValuePair.Value), keyValuePair.Key);
	}
}

private void AddFileContent(MultipartFormDataContent formContent, string outputfile, ProjectItem projectItem)
{
	var byteArrayContent = new ByteArrayContent(File.ReadAllBytes(outputfile));

	byteArrayContent.Headers.ContentType = new MediaTypeHeaderValue("application/x-zip-compressed");
	
	byteArrayContent.Headers.ContentDisposition = ContentDispositionHeaderValue.Parse("form-data");
	byteArrayContent.Headers.ContentDisposition.FileName = $"{projectItem.Title}.zip";
	
	// ContentDisposition.Name needs to match the parameter name
	byteArrayContent.Headers.ContentDisposition.Name = "file";

	formContent.Add(byteArrayContent);
}

 

Thanks,
-Joe

View solution in original post

0 Kudos
3 Replies
PreetiMaske
Esri Contributor

I believe you can call update only on an existing portal item so I suggest :

- Add PortalItem first then call update

- Enclose UpdateItemAsync() in try catch block to catch any errors.

0 Kudos
JoeHershman
MVP Regular Contributor

No exceptions are being thrown, it just does not return from the method call

Thanks,
-Joe
0 Kudos
JoeHershman
MVP Regular Contributor

Never found a way to get anything to work with the Runtime API, but was able to do using the rest endpoint directly.

 

string zipfileName = CreateProjectZipfile(projectItem);

/* Does not seem that Runtime API handles creating a zip file item, so using rest API directly
/*    https://developers.arcgis.com/rest/users-groups-and-items/add-item.htm */

string url = $"https://www.arcgis.com/sharing/rest/content/users/{portal.User?.UserName}/additem";

using ( var formContent = new MultipartFormDataContent() )
{
	AddStringContent(formContent, projectItem);
	AddFileContent(formContent, zipfileName, projectItem);

	using ( HttpClient client = new HttpClient(new ArcGISHttpClientHandler()) )
	{
		var response = await client.PostAsync(url, formContent);
		var json = await response.Content.ReadAsStringAsync();

		await ShareItemWithGroupAsync(json);
	}
}


private void AddStringContent(MultipartFormDataContent formContent, ProjectItem projectItem)
{
	Dictionary<string, string> parameters = new Dictionary<string, string>()
	{
		{ "multipart", "false" },
		{ "title", projectItem.Title },
		{ "type", "Code Sample" },
		{ "async", "false" },
		{ "f", "json" }
	};

	//  For MultipartFormDataContent paramaters needs to be added as individual StringContent objects.  FormUrlEncodedContent does not work.
	foreach (var keyValuePair in parameters)
	{
		formContent.Add(new StringContent(keyValuePair.Value), keyValuePair.Key);
	}
}

private void AddFileContent(MultipartFormDataContent formContent, string outputfile, ProjectItem projectItem)
{
	var byteArrayContent = new ByteArrayContent(File.ReadAllBytes(outputfile));

	byteArrayContent.Headers.ContentType = new MediaTypeHeaderValue("application/x-zip-compressed");
	
	byteArrayContent.Headers.ContentDisposition = ContentDispositionHeaderValue.Parse("form-data");
	byteArrayContent.Headers.ContentDisposition.FileName = $"{projectItem.Title}.zip";
	
	// ContentDisposition.Name needs to match the parameter name
	byteArrayContent.Headers.ContentDisposition.Name = "file";

	formContent.Add(byteArrayContent);
}

 

Thanks,
-Joe
0 Kudos