This repository has been archived by the owner on Nov 9, 2017. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 19
PostAttachmentsOperation
davetimmins edited this page Nov 20, 2014
·
2 revisions
If you want to post attachments then the in built gateway types won't work since they don't set the request body to the appropriate content.
Posting attachments requires a multipart form content body with some custom headers so you can use the code below.
Define the request and response types
public interface IAttachment
{
byte[] Attachment { get; }
string FileName { get; }
string ContentType { get; }
}
public class AttachmentToPost : ArcGISServerOperation, IAttachment
{
public AttachmentToPost(ArcGISServerEndpoint endpoint, long objectID, string attachmentBase64Encoded, string fileName, string contentType, bool isUpdate = false)
: this(endpoint, objectID, fileName, contentType, isUpdate)
{
Guard.AgainstNullArgument("attachmentBase64Encoded", attachmentBase64Encoded);
AttachmentBase64Encoded = attachmentBase64Encoded;
Attachment = Convert.FromBase64String(AttachmentBase64Encoded);
}
public AttachmentToPost(ArcGISServerEndpoint endpoint, long objectID, byte[] attachment, string fileName, string contentType, bool isUpdate = false)
: this(endpoint, objectID, fileName, contentType, isUpdate)
{
Guard.AgainstNullArgument("attachment", attachment);
Attachment = attachment;
AttachmentBase64Encoded = Convert.ToBase64String(Attachment);
}
AttachmentToPost(ArcGISServerEndpoint endpoint, long objectID, string fileName, string contentType, bool isUpdate = false)
{
Guard.AgainstNullArgument("endpoint", endpoint);
Endpoint = new ArcGISServerEndpoint(endpoint.RelativeUrl.Trim('/')
+ string.Format("/{0}/{1}", objectID, isUpdate ? "updateAttachment" : "addAttachment"));
ObjectID = objectID;
FileName = fileName;
ContentType = contentType;
}
public long ObjectID { get; private set; }
public string AttachmentBase64Encoded { get; private set; }
public byte[] Attachment { get; private set; }
public string FileName { get; private set; }
public string ContentType { get; private set; }
}
[DataContract]
public class AddAttachmentResponse : PortalResponse
{
[DataMember(Name = "addAttachmentResult")]
public PostAttachmentResult AddAttachmentResult { get; set; }
}
[DataContract]
public class PostAttachmentResult : PortalResponse
{
[DataMember(Name = "objectId")]
public long ObjectID { get; set; }
[DataMember(Name = "globalId")]
public string GlobalID { get; set; }
[DataMember(Name = "success")]
public bool Success { get; set; }
}
and then the gateway
public class AttachmentGateway : IPortalGateway, IDisposable
{
HttpClient _httpClient;
/// <summary>
/// Create an ArcGIS Server gateway to access secure resources
/// </summary>
/// <param name="rootUrl">Made up of scheme://host:port/site</param>
/// <param name="serializer">Used to (de)serialize requests and responses</param>
/// <param name="tokenProvider">Provide access to a token for secure resources</param>
public AttachmentGateway(string rootUrl, ISerializer serializer = null, ITokenProvider tokenProvider = null)
{
RootUrl = rootUrl.AsRootUrl();
TokenProvider = tokenProvider;
Serializer = serializer ?? SerializerFactory.Get();
if (Serializer == null) throw new ArgumentNullException("serializer", "Serializer has not been set.");
_httpClient = HttpClientFactory.Get();
}
~AttachmentGateway()
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_httpClient != null)
{
_httpClient.Dispose();
_httpClient = null;
}
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public string RootUrl { get; private set; }
public ITokenProvider TokenProvider { get; private set; }
public ISerializer Serializer { get; private set; }
async Task<Token> CheckGenerateToken(CancellationToken ct)
{
if (TokenProvider == null) return null;
var token = await TokenProvider.CheckGenerateToken(ct);
if (token != null) CheckRefererHeader(token.Referer);
return token;
}
void CheckRefererHeader(string referrer)
{
if (_httpClient == null || string.IsNullOrWhiteSpace(referrer)) return;
Uri referer;
bool validReferrerUrl = Uri.TryCreate(referrer, UriKind.Absolute, out referer);
if (!validReferrerUrl)
throw new HttpRequestException(string.Format("Not a valid url for referrer: {0}", referrer));
_httpClient.DefaultRequestHeaders.Referrer = referer;
}
public Task<AddAttachmentResponse> AddAttachment(AttachmentToPost attachment)
{
return AddAttachment(attachment, CancellationToken.None);
}
public Task<AddAttachmentResponse> AddAttachment(AttachmentToPost attachment, CancellationToken ct)
{
Guard.AgainstNullArgument("attachment", attachment);
Guard.AgainstNullArgumentProperty("attachment", "Attachment", attachment.Attachment);
return Post<AddAttachmentResponse, AttachmentToPost>(attachment, ct);
}
protected async Task<T> Post<T, TRequest>(TRequest requestObject, CancellationToken ct)
where TRequest : CommonParameters, IAttachment, IEndpoint
where T : IPortalResponse
{
var endpoint = requestObject;
var url = endpoint.BuildAbsoluteUrl(RootUrl).Split('?').FirstOrDefault();
var token = await CheckGenerateToken(ct);
if (ct.IsCancellationRequested) return default(T);
// these should have already been added
if (string.IsNullOrWhiteSpace(requestObject.Token) && token != null && !string.IsNullOrWhiteSpace(token.Value))
{
requestObject.Token = token.Value;
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(token.Value);
if (token.AlwaysUseSsl) url = url.Replace("http:", "https:");
}
_httpClient.CancelPendingRequests();
Uri uri;
bool validUrl = Uri.TryCreate(url, UriKind.Absolute, out uri);
if (!validUrl)
throw new HttpRequestException(string.Format("Not a valid url: {0}", url));
System.Diagnostics.Debug.WriteLine(uri);
string resultString = string.Empty;
var attachment = (IAttachment)requestObject;
using (var content = new MultipartFormDataContent())
{
var streamContent = new StreamContent(new MemoryStream(attachment.Attachment));
var header = new ContentDispositionHeaderValue("form-data");
header.Name = "\"attachment\"";
header.FileName = attachment.FileName;
streamContent.Headers.ContentDisposition = header;
streamContent.Headers.ContentType = new MediaTypeHeaderValue(attachment.ContentType);
content.Add(streamContent);
content.Add(new StringContent("json"), "f");
if (!string.IsNullOrWhiteSpace(requestObject.Token)) content.Add(new StringContent(requestObject.Token), "token");
try
{
using (var message = await _httpClient.PostAsync(uri, content))
{
message.EnsureSuccessStatusCode();
resultString = await message.Content.ReadAsStringAsync();
}
}
catch (TaskCanceledException)
{
return default(T);
}
}
var result = Serializer.AsPortalResponse<T>(resultString);
if (result.Error != null) throw new InvalidOperationException(result.Error.ToString());
return result;
}
}