I can't use the ServiceStack Client libraries and I've chosen to use the HttpClient PCL library instead. I can do all my Rest calls (and other json calls) without a problem, but I'm now stucked with uploading files.
A snippet of what I am trying to do:
var message = new HttpRequestMessage(restRequest.Method, restRequest.GetResourceUri(BaseUrl));
var content = new MultipartFormDataContent();
foreach (var file in files)
{
byte[] data;
bool success = CxFileStorage.TryReadBinaryFile(file, out data);
if (success)
{
var byteContent = new ByteArrayContent(data);
byteContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = System.IO.Path.GetFileName(file) ,
};
content.Add(byteContent);
}
}
message.Content = content;
Problem is now that I get a null reference exception (status 500) when posting. I doesn't get into the service. I see the call in the filterrequest, but that's it.
So I'm wondering what I do wrong and how I can pinpoint what is going wrong. How can I catch the correct error on the ServiceStack layer?
Related
I want to create endpoint that will stream video stream that is stored in azure CloudBlob. Here is snippet of my code:
public async Task<IActionResult> GetVideo(string videoId)
{
var videoStream = await _contentStorage.Get(videoId);
var fileStreamResult = new FileStreamResult(videoStream, mimeType);
fileStreamResult.EnableRangeProcessing = true;
return fileStreamResult;
}
and in ContentStorage
public async Task<StoredContent> Get(string id)
{
var block = _blobContainer.GetBlobClient(id);
var ms = await block.OpenReadAsync();
return ms;
}
I had everything working fine except iPhones and safari, after some debugging it turned out that my endpoint is returning 200 http code, but it should 206 - partial content. So I made some changes into my code, here is some snippet:
public async Task<IActionResult> GetVideo(string videoId)
{
var videoStream = await _contentStorage.Get(videoId);
var ms = new MemoryStream();
await videoStream.CopyToAsync(ms);
var fileStreamResult = new FileStreamResult(ms, mimeType);
fileStreamResult.EnableRangeProcessing = true;
return fileStreamResult;
}
Now when I test it on iphone or by postman response is 206, and it's working fine. But I thing that copping the video stream into new memorystream is a valid approach.
Correct me if I'm wrong but I understand this code as for every partial of the video, I'm downloading whole video from blob storage, cut it and then return just the piece within range.
It's not sure for me how to handle this case, is there any out of the box solution for that, or do I need to read range header from request and use OpenReadAsync with parameters as position and buffer side? Or there is another way?
Solution for me was to update Azure.Storage.Blobs library. I had 12.6.0 and after update to 12.7.0 it started working as expected, since they added:
Added seekability to BaseBlobClient.OpenRead().
Here is the code:
private AccessTokenInfo GetToken()
{
WebRequest webRequest = WebRequest.Create("https://oxford-speech.cloudapp.net/token/issueToken");
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.Method = "POST";
byte[] bytes = Encoding.ASCII.GetBytes(_requestDetails);
webRequest.ContentLength = bytes.Length;
try
{
using (Stream outputStream = webRequest.GetRequestStream())
{
outputStream.Write(bytes, 0, bytes.Length);
}
// ...
I have got the exception:
the underlying connection was closed could not establish trust relationship
How can I fit it ?
I hope I'm not missing something here...
The URL you're using isn't the one that generates tokens for the Text-to-Speech API as documented here. (The "Oxford" that's referenced in your URL refers to the Project Oxford which Cognitive Services was formerly known as.)
Also, WebRequest is deprecated. Use the System.Net.Http package instead.
The code to invoke the new REST endpoint then would look something like:
using (var client = new HttpClient())
using (var request = new HttpRequestMessage(HttpMethod.Post, "https://api.cognitive.microsoft.com/sts/v1.0/issueToken"))
{
request.Headers.Add("Ocp-Apim-Subscription-Key", "YOUR-KEY-HERE");
var response = await client.SendAsync(req);
var token = await response.Content.ReadAsStringAsync();
}
Finally, there are several client libraries that may get you around from writing any code to hit the REST services at all.
I am using the MS Graph .net SDK. Attempting to copy a sharepoint document library to another sharepoint document library.
If the file is approximately 38mb, a GatewayTimeout exception is thrown for an unknown error.
Either MS has a bug, or I am doing something incorrectly. Here is my code:
HttpRequestMessage hrm = new HttpRequestMessage(HttpMethod.Post, request.RequestUrl);
hrm.Content = new StringContent(JsonConvert.SerializeObject(request.RequestBody), System.Text.Encoding.UTF8, "application/json");
await client.AuthenticationProvider.AuthenticateRequestAsync(hrm);
HttpResponseMessage response = await client.HttpProvider.SendAsync(hrm);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
}
}
catch (Microsoft.Graph.ServiceException ex)
{
throw new Exception("Unknown Error");
}
Anyone see a problem here?
EDIT: Here is my revised code
public static async Task copyFile(Microsoft.Graph.GraphServiceClient client, string SourceDriveId, string SourceItemId, string DestinationDriveId, string DestinationFolderId, string FileName)
{
try
{
var destRef = new Microsoft.Graph.ItemReference()
{
DriveId = DestinationDriveId,
Id = DestinationFolderId
};
await client.Drives[SourceDriveId].Items[SourceItemId].Copy(null, destRef).Request().PostAsync();
//await client.Drives[SourceDriveId].Root.ItemWithPath(itemFileName).Copy(parentReference: dest).Request().PostAsync();
}
catch (Microsoft.Graph.ServiceException ex)
{
throw new Exception(ex.Message);
}
}
The above revised code continues to give the same error; however, tonight, it is also occurring on a 13.8mb file that previously had worked fine.
Logically, because the error doesn't occur for smaller files, I think it has something to do with file size.
The response is supposed to be a 202 with location header. See Copy Item in Graph Docs; however, I have never been able to obtain a location header. I suspect that Microsoft Graph is not getting the location header information from the OneDrive API and is therefore throwing a Gateway Timeout error.
I believe this is what you're looking for:
await graphClient.Drives["sourceDriveId"]
.Items["sourceItemId"]
.Copy(null, new ItemReference()
{
DriveId = "destinationDriveId",
Id = "destinationFolderId"
})
.Request()
.PostAsync();
This will take a given DriveItem and copy it to a folder in another Drive.
The web socket is written in javascript by my colleague. I managed to connect. First of all I have to log in on the application using a test account. I have to send the email and password through a json. I have installed the Json.Net packet using NuGet.
Some code that I found on my reaserch is this, but I do not understand how to send my data using that segment.
var buffer = new byte[1024];
var segment = new ArraySegment<byte>(buffer);
webSocket.SendAsync(segment, WebSocketMessageType.Text, true, CancellationToken.None);
Of course, I can use an object
User user=new User();
user.Email="bla#bla.com";
user.Password="pass";
string json = JsonConvert.SerializeObject(user);
But it will not be of any use because the method SendAsync accepts only byte type on segment.
All I want is to send that data, and if log in succeeds, I should receive other data (in Json format) about the user.
As a side note, I am quite new to web sockets, I used http protocols from ASP.NET WEB API 2.
I have no idea about Windows Phone 8, but by the code you pasted it seems similar to the regular .NET ClientWebSocket, so here you have some examples:
public static Task SendString(ClientWebSocket ws, String data, CancellationToken cancellation)
{
var encoded = Encoding.UTF8.GetBytes(data);
var buffer = new ArraySegment<Byte>(encoded, 0, encoded.Length);
return ws.SendAsync(buffer, WebSocketMessageType.Text, true, cancellation);
}
public static async Task<String> ReadString(ClientWebSocket ws)
{
ArraySegment<Byte> buffer = new ArraySegment<byte>(new Byte[8192]);
WebSocketReceiveResult result = null;
using (var ms = new MemoryStream())
{
do
{
result = await ws.ReceiveAsync(buffer, CancellationToken.None);
ms.Write(buffer.Array, buffer.Offset, result.Count);
}
while (!result.EndOfMessage);
ms.Seek(0, SeekOrigin.Begin);
using (var reader = new StreamReader(ms, Encoding.UTF8))
return reader.ReadToEnd();
}
}
If something does not compile or exists in WP8, just find an equivalent.
#vtortola is a working example in case your data comes in multiple segmented messages, but if all data comes in a single message you don't need all those streams to read the message, you just need to do this:
public static async Task<String> ReadString(ClientWebSocket socket)
{
var reciveBuffer = new byte[32000];
var result = await socket.ReceiveAsync(new ArraySegment<byte>(reciveBuffer), CancellationToken.None);
if (result.MessageType == WebSocketMessageType.Close)
{
await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
}
return Encoding.ASCII.GetString(reciveBuffer , 0, result.Count);
}
If your message is splited in multiple segments or you don't know how your message is comming then you have to do like #vtortola
Also if you want to keep receiving messages you can do a while and call ReadString inside, like this:
while (socket.State == WebSocketState.Open)
{
var msg = ReadString(socket)
//do something with your message...
}
I use the following method to upload a document into sharepoint document library.
However, upon executing the query - get the following error:
Message = "The remote server returned an error: (400) Bad Request."
the files are failing over 1mb, so i tested it via the sharepoint UI and the same file uploaded successfully.
any thoughts on what's the issue is? is it possible to stream the file over rather than 1 large file chunk? the file in question is only 3mb in size..
private ListItem UploadDocumentToSharePoint(RequestedDocumentFileInfo requestedDoc, ClientContext clientContext)
{
try
{
var uploadLocation = string.Format("{0}{1}/{2}", SiteUrl, Helpers.ListNames.RequestedDocuments,
Path.GetFileName(requestedDoc.DocumentWithFilePath));
//Get Document List
var documentslist = clientContext.Web.Lists.GetByTitle(Helpers.ListNames.RequestedDocuments);
var fileCreationInformation = new FileCreationInformation
{
Content = requestedDoc.ByteArray,
Overwrite = true,
Url = uploadLocation //Upload URL,
};
var uploadFile = documentslist.RootFolder.Files.Add(fileCreationInformation);
clientContext.Load(uploadFile);
clientContext.ExecuteQuery();
var item = uploadFile.ListItemAllFields;
item["Title"] = requestedDoc.FileNameParts.FileSubject;
item["FileLeafRef"] = requestedDoc.SharepointFileName;
item.Update();
}
catch (Exception exception)
{
throw new ApplicationException(exception.Message);
}
return GetDocument(requestedDoc.SharepointFileName + "." + requestedDoc.FileNameParts.Extention, clientContext);
}
EDIT: i did find the following ms page regarding my issue (which seems identical to the issue they have raised) http://support.microsoft.com/kb/2529243 but appears to not provide a solution.
ok found the solution here:
http://blogs.msdn.com/b/sridhara/archive/2010/03/12/uploading-files-using-client-object-model-in-sharepoint-2010.aspx
i'll need to store the document on the server hosting the file then using the filestream upload process i've done in my code below:
private ListItem UploadDocumentToSharePoint(RequestedDocumentFileInfo requestedDoc, ClientContext clientContext)
{
try
{
using(var fs = new FileStream(string.Format(#"C:\[myfilepath]\{0}", Path.GetFileName(requestedDoc.DocumentWithFilePath)), FileMode.Open))
{
File.SaveBinaryDirect(clientContext, string.Format("/{0}/{1}", Helpers.ListNames.RequestedDocuments, requestedDoc.FileName), fs, true);
}
}
catch (Exception exception)
{
throw new ApplicationException(exception.Message);
}
return GetDocument(requestedDoc.SharepointFileName + "." + requestedDoc.FileNameParts.Extention, clientContext);
}