I'm trying to save a PDF from QBO however I'm stuck on this bit:
How do i get the IConsumerRequest to return a stream instead of a string? ReadBody only seems to send string rather than binary data...
IConsumerRequest conReq = oSession.Request();
conReq = conReq.Get().WithRawContentType("application/pdf");
string outURL = base_url + "invoice-document/v2/" + realmId + "/" + customerInvoicesWithinDateRange[0].Id.Value;
conReq = conReq.ForUrl(outURL);
conReq = conReq.SignWithToken();
string serviceResponse = conReq.ReadBody();
Thanks
instead of conReeq.ReadBody(), you can do this:
conReq.ToWebResponse().GetResponseStream();
in fact, ReadBody() is simply an extension method on IConsumerRequest, defined as:
public static string ReadBody(this IConsumerRequest request)
{
HttpWebResponse response = request.ToWebResponse();
return response.ReadToEnd();
}
Related
I'm uploading to sharepoint using a c# client, and every file I Upload gets extra data included. A one line CSV file gets turned into a 7 line file that isn't usable. This is what my one line file upload turned into:
-----------AEE7A299-297A-41E0-B1CC-A72050FCDD28
Content-Disposition: form-data; name="ControlFile_RCTI_statement_20220218_145832.csv"; filename="ControlFile_RCTI_statement_20220218_145832.csv"
Content-Type: application/octet-stream
File;Class;Account Number;Effective Date;Product;Account Type;Document Name
-----------AEE7A299-297A-41E0-B1CC-A72050FCDD28--
My upload code is using restSharp
public async Task UploadFile(string filePath, string list, string folderPath)
{
await CheckTokenAsync();
var fileName = Path.GetFileName(filePath);
var endpoint = $"{spCredentials.sharepointSubSiteFullUrl}/_api/web/GetFolderByServerRelativeUrl('{list}/{folderPath}')/Files/Add(url='{fileName}', overwrite=false)";
var client = new RestClient(endpoint);
client.Timeout = 30000;
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", $"Bearer {token}");
request.AddHeader("Accept", "application/json;odata=verbose");
request.AddFile(fileName, filePath);
var response = await client.ExecuteAsync(request);
if (response.StatusCode == HttpStatusCode.OK)
{
var fileData = JsonConvert.DeserializeObject<SPSingleResultContainer>(response.Content);
var link = fileData.d.__metadata.uri;
await SendRequest<string>($"{link}/CheckIn()", Method.POST);
}
else
throw new Exception($"Upload Failed with message: " + response.ErrorMessage);
}
I've also added this question to the sharepoint SE at https://sharepoint.stackexchange.com/questions/300550/uploading-files-to-sharepoint-with-restsharp-and-their-rest-api-is-adding-header
Turned out RestSharp was doing a multipart upload, and sharepoint doesn't like that sort of thing. Other people have had This Issue with RestSharp
public async Task UploadFile(string filePath, string list, string folderPath)
{
var bytes = File.ReadAllBytes(filePath);
await UploadFileData(Path.GetFileName(filePath), list, folderPath, bytes);
return;
}
public async Task UploadFileData(string fileName, string list, string folderPath, byte[] fileData)
{
await CheckTokenAsync();
var endpoint = $"{spCredentials.sharepointSubSiteFullUrl}/_api/web/GetFolderByServerRelativeUrl('{list}/{folderPath}')/Files/Add(url='{fileName}', overwrite=false)";
var client = new RestClient(endpoint);
client.Timeout = 30000;
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", $"Bearer {token}");
request.AddHeader("Accept", "application/json;odata=verbose");
string contentType = "";
var fileType = Path.GetExtension(fileName).ToLower();
switch (fileType)//there are better ways to get the MIME type, I was just getting desperate and trying everything
{
case ".csv":
contentType = "text/csv";
break;
case ".xlsx":
contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
break;
case ".pdf":
contentType = "application/pdf";
break;
case ".html":
contentType = "text/html";
break;
default:
throw new NotImplementedException($"File type {fileType} not supported");
}
request.AddHeader("Content-Type", contentType);
request.AddParameter(contentType, fileData, ParameterType.RequestBody);
var response = await client.ExecuteAsync(request);
var test = JsonConvert.SerializeObject(request);
if (response.StatusCode == HttpStatusCode.OK)
{
var fileMetaData = JsonConvert.DeserializeObject<SPSingleResultContainer>(response.Content);
var link = fileMetaData.d.__metadata.uri;
await SendRequest<string>($"{link}/CheckIn()", Method.POST);
}
else
throw new Exception($"Upload {fileName} Failed with status {response.StatusCode} and message: " + response.ErrorMessage);
}
For anyone coming here that doesn't care about sharepoint, replacing .addfile with
request.AddHeader("Content-Type", contentType);
request.AddParameter(contentType, fileData, ParameterType.RequestBody);
where contentType is the MIME format of your file extension (or an empty string seems to work as well) solved the issue for me.
I'm trying to post a file in a json object to an external rest api over https. I have confirmed the json object is formatted correctly, do I have to do anything special to post to a rest api over https? I'm using the answer found over here as a guide: How to post JSON to the server?
private static void PostDatatoFTP(string FileName,
string fileString, string centerCode, string fileType) {
try {
byte[] plainTextBytes = Encoding.ASCII.GetBytes(fileString);
string base64File = Convert.ToBase64String(plainTextBytes);
FileInfo fileInfo = new FileInfo {
FileData = base64File,
FileName = FileName,
FileType = fileType,
FileVersion = _fileVersion
};
FileInfo[] transmitFileInfo = new FileInfo[1];
transmitFileInfo[0] = fileInfo;
Json jsonObject = new Json {
RequestType = _RequestType,
APIVersion = _apiVersion,
SubmissionId = Guid.NewGuid().ToString(),
UserId = _ftpUsername,
Password = _ftpPassword,
Vendor = _vendor,
CenterCode = centerCode,
FileInfo = transmitFileInfo
};
var json = JsonConvert.SerializeObject(jsonObject);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_uploadPath);
request.Method = "POST";
request.ContentType = "application/json";
using (var streamWriter = new StreamWriter(request.GetRequestStream())) {
streamWriter.Write(json);
}
var httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream() ?? throw new InvalidOperationException())) {
var result = streamReader.ReadToEnd();
Console.WriteLine(result);
}
}
catch (WebException e) {
Console.WriteLine(e.Message);
String status = ((HttpWebResponse)e.Response).StatusDescription;
Console.WriteLine(status);
}
catch (Exception ex) {
Console.WriteLine(ex.Message);
}
}
I'm trying to clear all azure storage queue message via Queue Service REST API. I've verified that the code is correct, but it still returns a 403 forbidden error. The "StorageSharedKey" and "StorageAccountName" are correct since I'm able to connect to the azure queue using those values in the connection string for the azure queue client. The storage version I'm using is "2015-12-11".
Here is the code:
internal void ClearStorageQueueMessages(string queueName)
{
const string requestMethod = "DELETE";
string urlPath = $"{queueName}/messages";
var dateInRfc1123Format = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
var canonicalizedHeaders = $"x-ms-date:{dateInRfc1123Format}\nx-ms-version:{StorageVersion}";
var canonicalizedResource = $"/{StorageAccountName}/{urlPath}";
var uri = new Uri($"https://{StorageAccountName}.queue.core.windows.net/{urlPath}");
var response = MakeDeleteRestCall(uri, requestMethod, dateInRfc1123Format, canonicalizedHeaders, canonicalizedResource);
}
internal RestResponse MakeDeleteRestCall(Uri uri, string requestMethod, string dateInRfc1123Format, string canonicalizedHeaders,
string canonicalizedResource)
{
var restResponse = new RestResponse();
var stringToSign = $"{requestMethod}\n\n\n\n\n\n\n\n\n\n\n\n{canonicalizedHeaders}\n{canonicalizedResource}";
var authorizationHeader = CreateAuthorizationHeader(stringToSign);
var request = (HttpWebRequest) WebRequest.Create(uri);
request.Method = requestMethod;
request.Headers.Add("x-ms-date", dateInRfc1123Format);
request.Headers.Add("x-ms-version", StorageVersion);
request.Headers.Add("Authorization", authorizationHeader);
//request.Accept = "application/atom+xml,application/xml";
request.Accept = "application/json";
//request.ContentType = "application/json";
using (var response = (HttpWebResponse) request.GetResponse())
{
restResponse.StatusCode = response.StatusCode;
var responseStream = response.GetResponseStream();
if (responseStream == null)
return restResponse;
using (var reader = new StreamReader(responseStream))
{
restResponse.ReturnedContent = reader.ReadToEnd();
}
}
return restResponse;
}
internal static string CreateAuthorizationHeader(string canonicalizedString)
{
string signature;
using (var hmacSha256 = new HMACSHA256(Convert.FromBase64String(StorageSharedKey)))
{
var dataToHmac = Encoding.UTF8.GetBytes(canonicalizedString);
signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
}
var authorizationHeader = string.Format(CultureInfo.InvariantCulture, "{0} {1}:{2}", StorageSharedKey,
StorageAccountName, signature);
return authorizationHeader;
}
The problem seems to be with the header Authorization. Please check the format according to the documentation:
Authorization="[SharedKey|SharedKeyLite] :"
https://msdn.microsoft.com/en-us/library/azure/dd179428.aspx
Your function adds the shared key in plain text instead of the authorization scheme "SharedKey" or "SharedKeyLite".
I am using this code but gives me this error:
Failed to retrieve data from the database. Details: [Database Vendor Code: 201 ]
public JsonResult ReportCertificateOfEmployment(int EmployeeId, int SigId, string SigPosition)
{
string Userkey = "gHeOai6bFzWskyUxX2ivq4+pJ7ALwbzwF55dZvy/23BrHAfvDVj7mg ";
string PassKey = "lLAHwegN8zdS7mIZyZZj+EmzlkUXkvEYxLvgAYjuBVtU8sw6wKXy2g ";
string rptlogin = ConfigurationManager.AppSettings.Get("rptlogin");
string rptPassword = ConfigurationManager.AppSettings.Get("rptPassword");
MemoryStream oStream;
CertificateOfEmployment rpt = new CertificateOfEmployment();
rpt.Refresh();
rpt.SetDatabaseLogon(rptlogin, rptPassword);
rpt.SetParameterValue(0, EmployeeId);
rpt.SetParameterValue(1, SigId);
rpt.SetParameterValue(2, SigPosition);
rpt.SetParameterValue(3, DateTime.Now);
oStream = (MemoryStream)rpt.ExportToStream(CrystalDecisions.Shared.ExportFormatType.PortableDocFormat); --------- this gives me an error
// extract only the fielname
string filename = Convert.ToString((DateTime.Now.Month) + Convert.ToString(DateTime.Now.Day) + Convert.ToString(DateTime.Now.Year) + Convert.ToString(DateTime.Now.Hour) + Convert.ToString(DateTime.Now.Minute) + Convert.ToString(DateTime.Now.Second) + Convert.ToString(DateTime.Now.Millisecond)) + "BarangayClearance";
var len = oStream.Length;
// store the file inside ~/App_Data/uploads folder
// var path = Path.Combine(Server.MapPath("~/Content/Images"), fileName);
// file.SaveAs(path);
FileTransferServiceClient client2 = new FileTransferServiceClient();
RemoteFileInfo rmi = new RemoteFileInfo();
DateTime dt = DateTime.Now;
// upload file using webservice
DownloadRequest dr = new DownloadRequest();
//web service method to upload a file and return the unique id of the newly uploaded file
string fId = client2.UploadFileGetId("", filename, len, PassKey, Userkey, oStream);
//Instantiate the object Img which is a table in the database server of the application
//Download file using web service;
//DownloadFile in Refence.cs has been edited to return a RemoteFileInfo Class
//before, the return type of DownloadFile method was a Stream type
JsonResult result = new JsonResult();
result.Data = new
{
fileId = fId,
filename = filename
};
rpt.Close();
rpt.Dispose();
var arr = oStream.ToArray();
oStream.Close();
oStream.Dispose();
result.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return result;
}
IF I remove
.spec(responseSpec)
from my call, the response prints fine at "FOO". If I include the builder, the response prints an empty string (even though the test is passing). Anyone know why, or how to fix this? I would like to use the builder and print the response of the passing test.
public void getCirclesId()
{
String endpoint = "getCirclesId";
String url = baseUrl + resourcePath + "/" + circleId;
RequestSpecification given = given().header("Authorization", RestTest.BEARER_TOKEN);
ResponseSpecBuilder specBuilder = new ResponseSpecBuilder();
specBuilder.expectBody("features.priceMonth", is("5.00"));
specBuilder.expectBody("features.priceYear", is("50.00"));
Response response = JsonTest.executeRequestWithSpec(given, url, resource, endpoint, JsonTest.HttpType.GET, specBuilder);
}
...
public static Response executeRequestWithSpec(RequestSpecification given, String url, String resource, String endpoint, HttpType type, ResponseSpecBuilder builder)
{
Response response = null;
try {
switch (type) {
case GET:
response = executeGetRequestWithSpec(given, url, builder);
break;
case POST:
response = executePostRequestWithSpec(given, url, builder);
break;
case PUT:
response = executePutRequestWithSpec(given, url, builder);
break;
case DELETE:
response = executeDeleteRequestWithSpec(given, url, builder);
break;
}
System.out.println(resource + " - " + endpoint + ": " + response.print());
} catch (AssertionError e) {
RestTest.failCount++;
System.err.println(resource + " - " + endpoint + " Error: " + e.getMessage());
}
return response;
}
private static Response executeGetRequestWithSpec(RequestSpecification given, String url, ResponseSpecBuilder builder)
{
ResponseSpecification responseSpec = builder.build();
Response response = given.when().get(url + ".json").then().assertThat().statusCode(200).spec(responseSpec).extract().response();
System.out.println("FOOOO" + response.print());
return response;
}
Are you using the latest version of REST Assured (currently 2.3.0)? Otherwise I suggest you to upgrade to this version. There was some problems with response specifications in 2.0.