Tweetsharp SendTweetWithMedia from url - c#

I am trying to use Tweetsharp's SendTweetWithMedia with a image which I don't have stored locally, I only have a url. All the examples I have found of SendTweetWithMedia use a file on the local system.
var thumb = "http://somesite.net/imageurl";
var service = new TwitterService(key, secret);
service.AuthenticateWith(token, tokenSecret);
var req = WebRequest.Create(thumb);
using (var stream = req.GetResponse().GetResponseStream())
{
response = service.SendTweetWithMedia(new SendTweetWithMediaOptions
{
Status = tweet.Trim(),
Images = new Dictionary<string, Stream> { { fullname, stream } }
});
}
I get the following error from SendTweetWithMedia:
'System.NotSupportedException': This stream does not support seek operations.
I could download the file from the url and save locally, but I'd rather use the url. Is this possible?

In the end, I just created a temporary file:
byte[] data;
using (var client = new WebClient())
{
data = client.DownloadData(thumb);
}
File.WriteAllBytes($"{Path.GetTempPath()}\\xyz.jpg", data);
best answer I could come up with. Still a few more lines than I'd like though.

Related

How can I create HttpRequest (in C#) with attached files?

As title says, can find plenty of resources on posting to an endpoint (from JS, for example), but how do I construct a HttpRequest (in C# .Net core) with files?
What I've Tried
var myRequest = new DefaultHttpContext().Request;
myRequest.Form.Files // GET only!
I can't seem to set the Files collection (IFormFileCollection), I can only get it.
Further Context
This is to integration test an endpoint. Except I have to hit the method, not reach it via URL (for one reason or another). The method accepts a HttpRequest and parses out the Form.Files collection. Hence I need to add some files for my assertions.
Did you already try something like this:
using (var stream = new MemoryStream(fileBytes))
{
var bla = new DefaultHttpContext().Request;
bla.Form.Files.Append(new Microsoft.AspNetCore.Http.Internal.FormFile(stream, 0, stream.Length, "file.txt", "file.txt"));
}
you can achieve this by take advantage of the following Method
public async Task<string> UploadFile(string filePath)
{
if (string.IsNullOrWhiteSpace(filePath))
{
throw new ArgumentNullException(nameof(filePath));
}
if (!File.Exists(filePath))
{
throw new FileNotFoundException($"File [{filePath}] not found.");
}
using var form = new MultipartFormDataContent();
using var fileContent = new ByteArrayContent(await File.ReadAllBytesAsync(filePath));
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
form.Add(fileContent, "file", Path.GetFileName(filePath));
form.Add(new StringContent("789"), "userId");
form.Add(new StringContent("some comments"), "comment");
form.Add(new StringContent("true"), "isPrimary");
var response = await _httpClient.PostAsync($"{_url}/api/files", form);
response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<FileUploadResult>(responseContent);
return result.Guid;
}
this method was snipped from a good blog: https://codeburst.io/upload-download-files-using-httpclient-in-c-f29051dea40c
It would look something like this:
var context = new DefaultHttpContext();
var formFiles = new FormFileCollection();
var formValues = new Dictionary<string, StringValues>() { };
var formCollection = new FormCollection(formValues, formFiles);
context.Features.Set<IFormFeature>(new FormFeature(formCollection));
Fill in the formFiles and formValues variables based on what you're trying to test. The key here is setting the feature to your custom FormFeature. That will cleanly plug into the default behavior of .Form and ReadFormAsync
PS: This is for unit testing assuming you're not trying to send a real file to the server side, otherwise mustafa hassan's answer works

How to send File Object to Web api using POST call in Xamarin forms.?

I need to make a POST call from my Xamarin forms app where I need to upload a file object as it is to API using POST Call. Is there any way to make it possible?
if you send file object using Base64 or Byte[] then it will allowed only limited may be upto 2-4 Mb but if you have a larger image than that it will not support.
So, Solution is Post Stream Content Like,
var file = await CrossMedia.Current.PickPhotoAsync(new PickMediaOptions
{
PhotoSize = PhotoSize.Full,
CompressionQuality = 100
});
Create Object of MediaFile like, public MediaFile AttachedImage; and Store file into it so Memory stream will not lost. Like,AttachedImage = file
Post Code on API,
HttpClient httpClient = new HttpClient();
MultipartFormDataContent mt = new MultipartFormDataContent();
AttachedImage.GetStream().Position = 0;
StreamContent imagePart = new StreamContent(AttachedImage.GetStream());
imagePart.Headers.Add("Content-Type", ImageType);
mt.Add(imagePart, String.Format("file"), String.Format("bk.jpeg"));
requestMessage.Content = mt;
var response = await httpClient.PostAsync("Your URL", mt);
if (response.IsSuccessStatusCode)
{
var responseString = await response.Content.ReadAsStringAsync();
var objRootObjectuploadImage = JsonConvert.DeserializeObject<RootObjectuploadImage>(responseString);
if (objRootObjectuploadImage != null)
{
}
else
{
}
}
else
{
Loading(ActIndicator, false);
await DisplayAlert(res.LAlert, "webserver not responding.", res.LOk);
}
NO, it is not possible to send file object. You can send as a json by converting the file in the Base64 string. This is the advised proven solution. This link has code for converting back and forth from Base64.

Microsoft Cognitive Services Vision API: Sending multipart data

I am trying to call the Microsoft Cognitive API by passing multiple images as per documentation and using the multipart/form-data, but I am getting an error that says "Unsupported Media Type". I have tried to use both ByteArray and StreamContent.
Api documentation.
private static byte[] GetImageAsByteArray(Stream fileStream)
{
using (var binaryReader = new BinaryReader(fileStream))
{
return binaryReader.ReadBytes((int)fileStream.Length);
}
}
static void Main(string[] args)
{
var uriBase = "https://westus.api.cognitive.microsoft.com/vision/v1.0/recognizeText";
var subscriptionKey = "<subscriptionKey>";
var client = new HttpClient();
var uri = string.Concat(uriBase, "?", "language=en&detectOrientation=true");
var images = new List<Stream>();
var img = Image.FromStream(File.Open("<imageName>", FileMode.Open));
var stream = new MemoryStream();
img.Save(stream, ImageFormat.Bmp);
stream.Position = 0;
images.Add(stream);
using (var content = new MultipartFormDataContent())
{
foreach (var image in images)
{
//content.Add(new StreamContent(stream));
content.Add(new ByteArrayContent(GetImageAsByteArray(image)));
}
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", subscriptionKey);
content.Headers.ContentType = new MediaTypeHeaderValue("multipart/form-data");
var response = client.PostAsync(uri, content).Result;
}
}
I am trying to call the Microsoft Cognitive API by passing multiple images as per documentation and using the multipart/form-data, but I am getting an error that says "Unsupported Media Type".
It is not possible to send multiple images, regardless of header.
Please refer to the documentation Step 2, it mentions:
The basic way to perform the Computer Vision API call is by uploading an image directly. This is done by sending a "POST" request with application/octet-stream content type together with the data read from the image.
Example code can be found here
Test environment here.
Notice regardless of header, it is still sending 1 image.
The limits also mention a single image.

C# Get Request Directus

recently i discovered this amazing cms called Directus, where you can manage your database and Tables with web request and Json.
Everything worked fine creating,updating,reading...till i came to the point where i want to Create (Upload) a Image using WebRequest.
Im basicly reading a image as Base64 and writing the data along with the parameters in the Uri using a simple GET request exactly like described in API.
Regardless what i try and use the Images Never show up in my Files.
Am i doing something wrong or forgetting something?
Or does directus want something else from me?
My first try:
public static async void UploadUserImage() {
var uri = "http://IP/Directus/api/1/files?access_token=SecretApiKey";
var data = GetImageData();
var finalUri = $"{uri}&data={data}";
using (var client = new HttpClient()) {
var responseString = await client.GetStringAsync(finalUri);
Console.Write(responseString);
}
}
My Second try with Json:
public static async void UploadUserImage() {
var uri = "http://IP/Directus/api/1/files?access_token=SecretApiKey";
var data = GetImageData();
var finalUri = $"{uri}&data={data}";
var postModel = new PictureModel {
data = data,
title = "Test",
name = "test"
};
using (var client = new HttpClient())
{
// Serialize our concrete class into a JSON String
var content = JsonConvert.SerializeObject(postModel);
var contenta = new StringContent(content, Encoding.UTF8, "application/json");
var response = await client.PostAsync(finalUri, contenta);
var result = await response.Content.ReadAsByteArrayAsync();
Console.Write(System.Text.Encoding.UTF8.GetString(result));
}
}
The docs is incorrect it's actually a POST request. Thanks for pointing that out.
To upload a new file you need three provide three values:
{
"name": "image.png",
"type": "image/png",
"data": "base64content"
}
The data content has to be in this format data:<mime-type>;base64,<data-content> so it will look something like this: data:image/png;base64,ThisIsABase64Content
We are updating the docs and removing the data:image/png which is unnecessary.

azure shared access signiture creation

I am using c# to create shared access signatures for new resources (The user should have create privileges to create new resources on my storage account).
The MS documentation is out of date and I can't seem to get it to work using the different blog posts I've gone through.
Right now my code looks like so:
public static string GetBlobSharedAccessSignitureUrl(CloudBlobContainer container,string nameOfBlobToCreateSaSfor)
{
var blob = container.GetBlockBlobReference(nameOfBlobToCreateSaSfor);
var policy = new SharedAccessBlobPolicy
{
SharedAccessExpiryTime = DateTime.Now.AddHours(1),
Permissions = SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Read
};
container.GetSharedAccessSignature(policy);
string sas = blob.GetSharedAccessSignature(policy);
return blob.Uri.AbsoluteUri + sas;
}
and the returned url (for my local machine) looks like this (what seems to be correct)
http://127.0.0.1:10000/devstoreaccount1/photos/photos_4.jpg?sv=2012-02-12&se=2013-01-20T10%3A13%3A17Z&sr=b&sp=rw&sig=xxx
I started the Azure storage simulator and through fiddler tried to POST to this URL (also tried PUT)
I am getting errors (404 or 400 , depends on different code for this function that I have tried)
Do I need to do something else? (In the old examples I saw them create a resource in that location before hand - which I've tried as well but didn't work either...)
Azure SDK version is 2.0 so the MS blog posts (and other tutorials) before October 2012 are broken (also according to MS dev blog http://blogs.msdn.com/b/windowsazurestorage/archive/2012/10/29/windows-azure-storage-client-library-2-0-breaking-changes-amp-migration-guide.aspx)
any help would be appreciated
If you're posting through Fiddler or through your code, please make sure you add "x-ms-blob-type" request header and set it's value as "BlockBlob". Take a look at this sample code where it tries to upload a file:
FileInfo fInfo = new FileInfo(fileName);//fileName is the full path of the file.
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(blobSaSUrl);
NameValueCollection requestHeaders = new NameValueCollection();
requestHeaders.Add("x-ms-blob-type", "BlockBlob");
req.Method = "PUT";
req.Headers.Add(requestHeaders);
req.ContentLength = fInfo.Length;
byte[] fileContents = new byte[fInfo.Length];
using (FileStream fs = fInfo.OpenRead())
{
fs.Read(fileContents, 0, fileContents.Length);
using (Stream s = req.GetRequestStream())
{
s.Write(fileContents, 0, fileContents.Length);
}
using (HttpWebResponse resp = (HttpWebResponse)req.GetResponse())
{
}
}
Create a SAS token that's valid for one hour.
BlobSasBuilder sasBuilder = new BlobSasBuilder()
{
BlobContainerName = containerName,
BlobName = blobName,
Resource = "b",
StartsOn = DateTimeOffset.UtcNow,
ExpiresOn = DateTimeOffset.UtcNow.AddHours(1)
};
Specify read permissions for the SAS.
sasBuilder.SetPermissions(BlobSasPermissions.Read);
Use the key to get the SAS token.
string sasToken = sasBuilder.ToSasQueryParameters(key, accountName).ToString();
Construct the full URI, including the SAS token.
UriBuilder fullUri = new UriBuilder()
{
Scheme = "https",
Host = string.Format("{0}.blob.core.windows.net", accountName),
Path = string.Format("{0}/{1}", containerName, blobName),
Query = sasToken
};

Categories