I'm tring to get an album picture from facebook using the facebook C# SDK within Silverlight app with the following code:
FacebookClient client = new FacebookClient(this.Profile.AccessToken);
client.GetAsync(string.Format("/{0}/picture?type=small", this.ID));
client.GetCompleted += (s, e) =>
{
dynamic result = e;
};
Where this.ID is the ID of the album, but I get this error:
Unexpected character encountered while parsing value: �. Line 1, position 1.
from the DeserializeObject method in the JsonSerializer. The problem is that facebook does'n return json data with the imge uri or something like this, but they actually return the image itself in a binary data. Anybody has any idea how I can handle this result or just get Uri to the image?
I have a workaround for this using this code:
var request = WebRequest.Create(string.Format("https://graph.facebook.com/{0}/picture?access_token={1}", this.ID, this.Profile.AccessToken));
request.BeginGetResponse(ar =>
{
using (var response = ((WebRequest)ar.AsyncState).EndGetResponse(ar))
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
this.Picture = new BitmapImage(new Uri(response.ResponseUri.AbsoluteUri));
}
);
}
}, request);
But I really wanted to use only Facebook C# SDK for getting the data.
Here is the solution that I'm going to use:
FacebookClient client = new FacebookClient(this.Profile.AccessToken);
client.QueryAsync(String.Format("SELECT src_small, src_big, src FROM photo WHERE pid IN (SELECT cover_pid FROM album WHERE object_id={0})", this.ID));
client.GetCompleted += (s, e) =>
{
dynamic result = e.GetResultData();
Deployment.Current.Dispatcher.BeginInvoke(() => this.Picture = result[0].src_small);
};
I was facing a similar issue. Wanted to use Facebook C# SDK only as well.
Solved it like this:
FacebookClient facebookAlbumClient = new FacebookClient(_albumAccessToken);
dynamic facebookAlbumCover = facebookAlbumClient.Get(string.Format("/{0}?fields=picture&type=thumbnail", (string)facebookAlbum["id"]));
This way you are getting the json array and not the picture
I think I found an acceptable solution for my problem. I'll just use FQL instead of Graph API. This will do the job:
FacebookClient client = new FacebookClient(this.Profile.AccessToken);
client.QueryAsync(String.Format("SELECT src_small, src_big, src FROM photo WHERE pid IN (SELECT cover_pid FROM album WHERE object_id={0})", this.ID));
client.GetCompleted += (s, e) =>
{
dynamic result = e.GetResultData();
Deployment.Current.Dispatcher.BeginInvoke(() => this.Picture = result[0].src_small);
};
Related
How can I use dotnetbrowser doing the following in a winform application?
Create a listener that listen for callbacks to a specific redirect url.
Open url in dotnetbrowser. The url makes the callback to the redirect url in another thread
The listener catches the response from the callback.
I can do this with an ordinary webbrowser, but I would like it to be silent. That's why I try to use dotnetbrowser instead.
Is dotNetBrowser a good choice for this, or is there a better option?
This is from my test code with a non silent webbrowser. First I create a listener that listen to a redirectUri:
var listener = new HttpListener();
listener.Prefixes.Add(redirectURI);
listener.Start();
Then I start the url in a webbrowser:
Process p = Process.Start(url);
The started url will send a callback to the redirectUri. The listener will get it.
var context = await listener.GetContextAsync(); ;
string formData = string.Empty;
using (var body = context.Request.InputStream)
{
using (var reader = new System.IO.StreamReader(body, context.Request.ContentEncoding))
{
formData = reader.ReadToEnd();
}
}
listener.Close();
I found a solution with help from dotnetbrowser support site.
This is the winform constructor in my new test project:
public Form1()
{
webView = new BrowserView() { Dock = DockStyle.Fill };
Task.Run(() =>
{
engine = EngineFactory.Create(new EngineOptions.Builder
{
RenderingMode = RenderingMode.HardwareAccelerated,
LicenseKey = "your license key here"
}
.Build());
browser = engine.CreateBrowser();
})
.ContinueWith(t =>
{
webView.InitializeFrom(browser);
var listener = new HttpListener();
listener.Prefixes.Add(redirectURI);
listener.Start();
browser.Navigation.LoadUrl(url);
var context = listener.GetContextAsync().GetAwaiter().GetResult();
//Get data from redirectUri. You find this code from test example above, but not really relevant for the problem.
var formData = GetRequestPostData(context.Request);
listener.Close();
}, TaskScheduler.FromCurrentSynchronizationContext());
InitializeComponent();
FormClosing += Form1_FormClosing;
Controls.Add(webView);
this.Visible = false;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
browser?.Dispose();
engine?.Dispose();
}
I am new to Microsoft graph so this might be a dumb question.
So I am writing a command line application trying to update a page in our team onenote. (enterprise onenote)
Here is the code I got work getting the token.
https://login.microsoftonline.com/common/oauth2/authorize?client_id=my_client_Id&response_type=code&redirect_uri=Some_uri&resource=https://graph.microsoft.com&scope=Notes.ReadWrite.All
I got the token as strCode and trying to retrieve all the notes under this account by these codes:
var baseAddress = new Uri("https://graph.microsoft.com/v1.0/me/onenote");
using (var httpClient = new HttpClient { BaseAddress = baseAddress })
{
var request = new HttpRequestMessage(HttpMethod.Get, #"/pages");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", strCode);
using (var response = httpClient.SendAsync(request).Result)
{
string responseData = response.Content.ReadAsStringAsync().Result;
}
}
And in the response data I got
"{ \"error\": { \"code\": \"InvalidAuthenticationToken\", \"message\": \"CompactToken parsing failed with error code: -2147184105\", \"innerError\": { \"request-id\": \"*********************", \"date\": \"2017-06-08T18:25:06\" } } }"
Any idea how to fix this..?
Problem resolved .
I need to convert the authentication code into a "real" access token..
The one that I got is not an access token.
I want to post to a web page from my Silverlight application and have the web page appear in a new window.
I can show a web page in a new window using the GET method, using the following code:
var options = new HtmlPopupWindowOptions();
HtmlPage.PopupWindow(new Uri("http://localhost:12345/test.aspx"), "_blank", options);
I can post to a web page and get the resulting data back using this code:
var request = (HttpWebRequest)WebRequest.Create(new Uri("http://localhost:12345/test.aspx"));
request.Method = "POST";
request.ContentType = "text/xml";
request.BeginGetRequestStream(requestResult =>
{
using (var stream = request.EndGetRequestStream(requestResult))
{
using (var writer = new StreamWriter(stream))
{
writer.Write("hello");
}
}
request.BeginGetResponse(responseResult =>
{
var response = request.EndGetResponse(responseResult);
using (var stream = response.GetResponseStream())
{
using (var reader = new StreamReader(stream))
{
var str = reader.ReadToEnd();
}
}
}, null);
}, null);
But what I can't do is the two together - post to the page but instead of getting the data back have the resulting page shown in a browser window. I don't know if this is possible, but any help to achieve this would be much appreciated.
I have the following simple application page that uses the phone camera to upload the taken photo to azure blob:
public partial class AddReport : PhoneApplicationPage
{
// blobs stuff
string storageAccount = "MYACCOUNT";
string storageKey = "MYKEY";
string blobServiceUri = "http://MYACCOUNT.blob.core.windows.net";
CloudBlobClient blobClient;
private Report newReport;
public AddReport()
{
InitializeComponent();
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
//base.OnNavigatedTo(e);
newReport = new Report();
var credentials = new StorageCredentialsAccountAndKey(storageAccount, storageKey);
blobClient = new CloudBlobClient(blobServiceUri, credentials);
}
private void TakePhotoClick(object sender, EventArgs eventArgs)
{
//The camera chooser used to capture a picture.
CameraCaptureTask ctask;
//Create new instance of CameraCaptureClass
ctask = new CameraCaptureTask();
//Create new event handler for capturing a photo
ctask.Completed += new EventHandler<PhotoResult>(ctask_Completed);
//Show the camera.
ctask.Show();
}
void ctask_Completed(object sender, PhotoResult e)
{
if (e.TaskResult == TaskResult.OK && e.ChosenPhoto != null)
{
WriteableBitmap CapturedImage = PictureDecoder.DecodeJpeg(e.ChosenPhoto);
UploadToBlobContainer(e.ChosenPhoto);
}
else
{
//user decided not to take a picture
}
}
private void UploadToBlobContainer(System.IO.Stream stream)
{
string containerName = "reportsPhotos";
var container = blobClient.GetContainerReference(containerName);
container.CreateIfNotExist(true, r =>
Dispatcher.BeginInvoke(() =>
{
var blobName = "report" + newReport.ReportId.ToString();
var blob = container.GetBlobReference(blobName);
blob.Metadata["ReportId"] = newReport.ReportId.ToString();
blob.UploadFromStream(stream, r2 =>
Dispatcher.BeginInvoke(() =>
{
newReport.Photo = container.Uri + "/" + blobName;
}));
}));
}
}
This is a simple case and I am not using SAS to authenticate, instead I save the key in the app itself (this is only for testing purposes) and also my blobs are publicly available.
when I run in debug mode it seems that everything is working, but the photo doesn't get uploaded to the blob. Also, I don't know how I can debug this to see if there was any error from the blob service.
Can anyone tell me what might be wrong ?
EDIT1: it seems that the container is not being created either. i've confirmed this using azure blob explorer
EDIT2: I am getting a System.Net.WebException : "The remote server returned an error: NotFound."
After long hours I have finally discovered that the problem was with this line:
string containerName = "reportsPhotos";
According to here all letters in a container name must be lowercase.
Changing it to reportsphotos solved the issue
That was time well spent.
Can you try just doing it like this instead:
// Retrieve storage account from connection-string
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
RoleEnvironment.GetConfigurationSettingValue("StorageConnectionString"));
// Create the blob client
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
// Retrieve reference to a previously created container
CloudBlobContainer container = blobClient.GetContainerReference("mycontainer");
// Retrieve reference to a blob named "myblob"
CloudBlob blob = container.GetBlobReference("myblob");
// Create or overwrite the "myblob" blob with contents from a local file
using (var fileStream = System.IO.File.OpenRead(#"path\myfile"))
{
blob.UploadFromStream(fileStream);
}
This is from:
http://www.windowsazure.com/en-us/develop/net/how-to-guides/blob-storage/#upload-blob
I have a problem with crossdomain.xml that is located on Facebook photo servers. The first problem arises when Silverlight asks for clientaccesspolicy.xml – Facebook servers return 403 – Access Denied which is fine, since they also have crossdomain.xml deployed on their servers. Silverlight then asks for that crossdomain.xml and the response it gets is exactly this:
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain- policy.dtd">
<cross-domain-policy>
<allow-access-from domain="*" secure="false" to-ports="*" />
<site-control permitted-cross-domain-policies="master-only" />
</cross-domain-policy>
Then I played for a while with this, deployed that crossdomain.xml to my own servers and a got the same results – a security exception. Then I started moving things out and came to a conclusion that everything will work as desired if I only remove the to-ports="*" attribute? Does anyone has an idea how to overcome this, has anyone had the same problem before or is it something that I’m doing wrong?
I have run into the same issue while trying to programmatically retrieve images from Facebook. The strange part is that if you point a Silverlight image control to the Facebook image url, the image is retrieved and displayed without error. This got me thinking and I have come up with a viable workaround that seems to work consistently for my situation. I hope you find it useful too.
var uri = new Uri("http://graph.facebook.com/mglace/picture/", UriKind.Absolute);
var bmp = new BitmapImage();
bmp.ImageOpened += (sender, e) => { /* Do something here with the sender (which is the BitmapImage) */ };
bmp.CreateOptions = BitmapCreateOptions.None;
bmp.UriSource = uri;
Create a BitmapImage object, set an event handler for the ImageOpened event and set the CreateOptions property to BitmapCreateOptions.None. Finally, set the UriSource to the Facebook image you want to retrieve. The image is downloaded immediately because we set the CreateOptions to None (the default value is DelayedCreation). You can then perform any actions you would like in the ImageOpened event handler.
I wanted to encapsulate this logic in my service layer and beef up the error handling and such so I wrapped it in a Reactive Extensions observable to make it easier to use. Here is my final code snippet:
public IObservable<BitmapImage> GetProfilePhoto(string profileId)
{
return Observable.Create<BitmapImage>(
observer =>
{
// This handler handles a successful fetch
EventHandler<RoutedEventArgs> openedHandler =
(sender, args) =>
{
try
{
observer.OnNext(sender as BitmapImage);
observer.OnCompleted();
}
catch (Exception ex)
{
observer.OnError(ex);
}
};
// This handler handle a failure
EventHandler<ExceptionRoutedEventArgs> failedHandler =
(sender, args) => observer.OnError(args.ErrorException);
var url = string.Format("http://graph.facebook.com/{0}/picture/", profileId);
var uri = new Uri(url, UriKind.Absolute);
BitmapImage bmp = null;
try
{
Deployment.Current.Dispatcher.BeginInvoke(
() =>
{
bmp = new BitmapImage();
bmp.ImageOpened += openedHandler;
bmp.ImageFailed += failedHandler;
bmp.CreateOptions = BitmapCreateOptions.None;
bmp.UriSource = uri;
});
}
catch (Exception ex)
{
observer.OnError(ex);
}
return () =>
{
// Cleanup the event handlers
if (bmp != null)
{
bmp.ImageOpened -= openedHandler;
bmp.ImageFailed -= failedHandler;
}
};
});
}
And usage:
GetProfilePhoto("mglace")
.Subscribe(image => { /* Do something with the image in here*/ },
error => { /* Handle any errors in here */ },
() => { /* Finalization code goes here */ });
I hope someone out there finds this useful.
This is still not resolved in Silverlight 5. Facebook doesn't seem concerned too.