Not calling method OnMessageReceived in xamarin - c#

I am implementing remote notification on android using xamarin.
I am doing POC using Walkthrough - Using Remote Notifications in Xamarin.Android
I am not getting notification on mobile, after registering mobile and send notification through sender using GCM.
Is there any mistake in code? or Can I track my notification to get detail why it is not come in mobile?
MyGcmListenerService.cs
[Service(Exported = false), IntentFilter(new[] { "com.google.android.c2dm.intent.RECEIVE" })]
public class MyGcmListenerService : GcmListenerService
{
public override void OnMessageReceived(string from, Bundle data)
{
var message = data.GetString("message");
Log.Debug("MyGcmListenerService", "From: " + from);
Log.Debug("MyGcmListenerService", "Message: " + message);
SendNotification(message);
}
....
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.yourcompany.LeaveApplication" android:installLocation="auto" android:versionCode="1" android:versionName="1.0">
<uses-sdk android:minSdkVersion="15" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.yourcompany.LeaveApplication.permission.C2D_MESSAGE" />
<permission android:name="com.yourcompany.LeaveApplication.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<application android:label="XamarinLeaveApp" >
<receiver android:name="com.google.android.gms.gcm.GcmReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.yourcompany.LeaveApplication" />
</intent-filter>
</receiver>
</application>
</manifest>
Message Sender's code
var jGcmData = new JObject();
var jData = new JObject();
jData.Add("message", MESSAGE);
jGcmData.Add("to", "/topics/global");
jGcmData.Add("data", jData);
var url = new Uri("https://gcm-http.googleapis.com/gcm/send");
try
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.TryAddWithoutValidation(
"Authorization", "key=" + API_KEY);
Task.WaitAll(client.PostAsync(url,
new StringContent(jGcmData.ToString(), Encoding.Default, "application/json"))
.ContinueWith(response =>
{
var response1 = response;
// Console.WriteLine(response);
//Console.WriteLine("Message sent: check the client device notification tray.");
}));
}
}
RegistrationIntentService.cs
[Service(Exported = false)]
class RegistrationIntentService : IntentService
{
static object locker = new object();
public RegistrationIntentService() : base("RegistrationIntentService") { }
protected override void OnHandleIntent(Intent intent)
{
try
{
Log.Info("RegistrationIntentService", "Calling InstanceID.GetToken");
lock (locker)
{
var instanceID = InstanceID.GetInstance(Application.Context);
var token = instanceID.GetToken(
"<project number", GoogleCloudMessaging.InstanceIdScope, null);
Log.Info("RegistrationIntentService", "GCM Registration Token: " + token);
SendRegistrationToAppServer(token);
Subscribe(token);
}
}
catch (Exception e)
{
Log.Debug("RegistrationIntentService", "Failed to get a registration token");
return;
}
}
void SendRegistrationToAppServer(string token)
{
// Add custom implementation here as needed.
}
void Subscribe(string token)
{
var pubSub = GcmPubSub.GetInstance(Application.Context);
pubSub.Subscribe(token, "/topics/global", null);
}
}

in the RegistrationIntentService.cs file, you use Application.Context instead of this. It should be equivalent, but can you try?
Also, I do not see in your code the protected override void OnCreate method that registers the RegistrationIntentService intent. Didn't you paste it here or did you forget to implement it?
HTH

Related

Repeating Notifications Lost After Android Device Reboot Xamarin Forms App C#

I am working on a Xamarin Forms app in C#. I followed this tutorial to setup local notifications that are repeating:
https://www.c-sharpcorner.com/article/how-to-send-local-notification-with-repeat-interval-in-xamarin-forms/
For the most part everything works with regards to the notifications firing. However if I reboot the device I no longer get any notifications.
Here is my broadcast receiver class:
[BroadcastReceiver(Enabled = true, Label = "Local Notifications Broadcast Receiver")]
[IntentFilter(new[] { Intent.ActionBootCompleted })]
public class ScheduledAlarmHandler : BroadcastReceiver
{
public const string LocalNotificationKey = "LocalNotification";
NotificationManager manager;
const string channelId = "default";
const string channelName = "Default";
const string channelDescription = "The default channel for notifications.";
public const string TitleKey = "title";
public const string MessageKey = "message";
bool channelInitialized = false;
public override void OnReceive(Context context, Intent intent)
{
if (!channelInitialized)
{
CreateNotificationChannel();
}
ComponentName receiver = new ComponentName(AndroidApp.Context, Class.FromType(typeof(ScheduledAlarmHandler)).Name);
PackageManager pm = AndroidApp.Context.PackageManager;
pm.SetComponentEnabledSetting(receiver, ComponentEnabledState.Enabled, ComponentEnableOption.DontKillApp);
var extra = intent.GetStringExtra(LocalNotificationKey);
var notification = DeserializeNotification(extra);
// Generating notification
var builder = new NotificationCompat.Builder(AndroidApp.Context, channelId)
.SetContentTitle(notification.Title)
.SetContentText(notification.Body)
.SetSmallIcon(notification.IconId)
.SetSound(RingtoneManager.GetDefaultUri(RingtoneType.Ringtone))
.SetAutoCancel(true);
var resultIntent = AndroidNotificationManager.GetLauncherActivity();
resultIntent.SetFlags(ActivityFlags.NewTask | ActivityFlags.ClearTask);
var stackBuilder = Android.Support.V4.App.TaskStackBuilder.Create(AndroidApp.Context);
stackBuilder.AddNextIntent(resultIntent);
Random random = new Random();
int randomNumber = random.Next(9999 - 1000) + 1000;
var resultPendingIntent =
stackBuilder.GetPendingIntent(randomNumber, (int)PendingIntentFlags.CancelCurrent);
builder.SetContentIntent(resultPendingIntent);
// Sending notification
var notificationManager = NotificationManagerCompat.From(AndroidApp.Context);
var notificationToNotify = builder.Build();
notificationManager.Notify(randomNumber, notificationToNotify);
}
private LocalNotification DeserializeNotification(string notificationString)
{
var xmlSerializer = new XmlSerializer(typeof(LocalNotification));
using (var stringReader = new StringReader(notificationString))
{
var notification = (LocalNotification)xmlSerializer.Deserialize(stringReader);
return notification;
}
}
void CreateNotificationChannel()
{
manager = (NotificationManager)AndroidApp.Context.GetSystemService(AndroidApp.NotificationService);
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
var channelNameJava = new Java.Lang.String(channelName);
var channel = new NotificationChannel(channelId, channelNameJava, NotificationImportance.Default)
{
Description = channelDescription
};
manager.CreateNotificationChannel(channel);
}
channelInitialized = true;
}
}
The tutorial didn't have the IntentFilter attribute added to the class or updates to the manifest file, but I added those in later while searching for solutions.
Here is my AndroidManifest file:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.service_buddy">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" />
<application android:label="Service_Buddy.Android"></application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application>
<receiver android:name="ServiceBuddy.Droid.ScheduledAlarmHandler" android:enabled="true" android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"></action>
</intent-filter>
</receiver>
</application>
</manifest>```
As far as I know , After rebooting there is no memory ,it is gone , therefor there is nothing to do job .
Don't waste your time , just use Shiny , it is a real problem solver in realm of background and foreground service in xamarin .
shiny getting started

plain text with share option list gives error

Okay so i have a weird error here that i can't figure out. I am sharing data with share option list in android "android.intent.action.SEND".
Sharing single image works perfectly, but when i try to share just plain text such as "asdfdgdsfsa", the program throws this error
"Java.Lang.RuntimeException: Unable to instantiate activity
ComponentInfo{com.companyname.Revamp/Revamp.RecieveDataFromApp.RecieveDataFromApp}:
java.lang.ClassNotFoundException: Didn't find class
"Revamp.RecieveDataFromApp.RecieveDataFromApp" on path:
DexPathList[[zip file
"/data/app/com.companyname.Revamp-HFm6SmD1Y-A76OQwcwCXIA==/base.apk"],nativeLibraryDirectories=[/data/app/com.companyname.Revamp-HFm6SmD1Y-A76OQwcwCXIA==/lib/x86,
/system/fake-libs,
/data/app/com.companyname.Revamp-HFm6SmD1Y-A76OQwcwCXIA==/base.apk!/lib/x86,
/system/lib, /vendor/lib]] ".
protected override void OnCreate(Bundle bundle)
{
Intent intent = Intent;
String action = Intent.Action;
String type = intent.Type;
if (Intent.ActionSend.Equals(action) && type != null)
{
// This is what we are trying to get working here.
if ("text/plain".Equals(type))
{
// Handle text being sent
// ...
// ...
// ...
}
else if (type.StartsWith("image/"))
{
// Handle single image being sent
// ...
// ...
// ...
}
}
else if (Intent.ActionSendMultiple.Equals(action) && type != null)
{
//This works
if (type.StartsWith("image/"))
{
// Handle multiple images being sent
// ...
// ...
// ...
}
}
else
{
// Handle other intents, such as being started from the home screen
}
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
LoadApplication(new App());
}
<activity android:name="Revamp.RecieveDataFromApp.RecieveDataFromApp" android:icon="#drawable/ic_home">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND_MULTIPLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.GET_CONTENT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="*/*" />
</intent-filter>
</activity>
I have tested your code and reproduce the issue. You could try to set the intent-filter in code, not in AndroidManifest.xml.
For example:
[Activity(Label = "RecieveDataFromApp", Icon = "#drawable/icon", Theme = "#style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
[IntentFilter(new[] { Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataMimeType = "image/*", Label = "RecieveDataFromApp")]
[IntentFilter(new[] { Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataMimeType = "text/plain", Label = "RecieveDataFromApp")]
[IntentFilter(new[] { Intent.ActionSendMultiple }, Categories = new[] { Intent.CategoryDefault }, DataMimeType = "image/*", Label = "RecieveDataFromApp")]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
...
...
...
}

xamarin.forms GCM Not Receiving Messages

I'm trying to implement Notifications via GCM in my Xamarin.Forms Project. Here is my code
MainActivity
using Android.App;
using Android.Content.PM;
using Android.OS;
using Android.Gms.Common;
using Android.Content;
namespace AIA.Droid
{
[Activity (Theme = "#style/MyTheme",
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
{
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
global::Xamarin.Forms.Forms.Init (this, bundle);
LoadApplication (new AIA.App ());
var x = typeof(Xamarin.Forms.Themes.DarkThemeResources);
x = typeof(Xamarin.Forms.Themes.LightThemeResources);
x = typeof(Xamarin.Forms.Themes.Android.UnderlineEffect);
if (IsPlayServicesAvailable())
{
var intent = new Intent(this, typeof(RegistrationIntentService));
StartService(intent);
}
}
public bool IsPlayServicesAvailable()
{
int resultCode = GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.Success)
return false;
else
return true;
}
}
}
My RegistrationIntentService.cs
Here ************ is my application number received from Google Play API Console
using System;
using Android.App;
using Android.Content;
using Android.Util;
using Android.Gms.Gcm;
using Android.Gms.Gcm.Iid;
namespace AIA.Droid
{
[Service(Exported = false)]
class RegistrationIntentService : IntentService
{
static object locker = new object();
public RegistrationIntentService() : base("RegistrationIntentService") { }
protected override void OnHandleIntent(Intent intent)
{
try
{
Log.Info("RegistrationIntentService", "Calling InstanceID.GetToken");
lock (locker)
{
var instanceID = InstanceID.GetInstance(this);
var token = instanceID.GetToken(
"************", GoogleCloudMessaging.InstanceIdScope, null);
Log.Info("RegistrationIntentService", "GCM Registration Token: " + token);
SendRegistrationToAppServer(token);
Subscribe(token);
}
}
catch (Exception e)
{
Log.Debug("RegistrationIntentService", "Failed to get a registration token");
return;
}
}
void SendRegistrationToAppServer(string token)
{
// Add custom implementation here as needed.
}
void Subscribe(string token)
{
var pubSub = GcmPubSub.GetInstance(this);
pubSub.Subscribe(token, "/topics/global", null);
}
}
}
My MyGcmListenerService.cs
using Android.App;
using Android.Content;
using Android.OS;
using Android.Gms.Gcm;
using Android.Util;
namespace AIA.Droid
{
[Service(Exported = false), IntentFilter(new[] { "com.google.android.c2dm.intent.RECEIVE" })]
public class MyGcmListenerService : GcmListenerService
{
public override void OnMessageReceived(string from, Bundle data)
{
var message = data.GetString("message");
Log.Debug("MyGcmListenerService", "From: " + from);
Log.Debug("MyGcmListenerService", "Message: " + message);
SendNotification(message);
}
void SendNotification(string message)
{
var intent = new Intent(this, typeof(MainActivity));
intent.AddFlags(ActivityFlags.ClearTop);
var pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.OneShot);
var notificationBuilder = new Notification.Builder(this)
.SetSmallIcon(Resource.Drawable.Icon)
.SetContentTitle("Akola Industries Association")
.SetContentText(message)
.SetDefaults(NotificationDefaults.Sound)
.SetContentIntent(pendingIntent);
var notificationManager = (NotificationManager)GetSystemService(Context.NotificationService);
notificationManager.Notify(0, notificationBuilder.Build());
}
}
}
Finally My AndroidMainfeast
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.AIA.Droid" android:installLocation="auto" android:versionCode="1" android:versionName="1.0">
<uses-sdk android:minSdkVersion="16" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.AIA.Droid.permission.C2D_MESSAGE" />
<uses-permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"></uses-permission>
<permission android:name="com.AIA.Droid.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<application android:label="AIA" android:icon="#drawable/Icon">
<receiver android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.AIA.Droid" />
</intent-filter>
</receiver>
</application>
</manifest>
All the above code are in my client App for receiving notifications
Now here is code how I'm sending messages
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
namespace MessageSender
{
class Program
{
public const string API_KEY = "My_API_Key";
public const string MESSAGE = "Welcome to AIA";
static void Main(string[] args)
{
var jGcmData = new JObject();
var jData = new JObject();
jData.Add("message", MESSAGE);
jGcmData.Add("to", "/topics/global");
jGcmData.Add("data", jData);
var url = new Uri("https://gcm-http.googleapis.com/gcm/send");
try
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.TryAddWithoutValidation(
"Authorization", "key=" + API_KEY);
Task.WaitAll(client.PostAsync(url,
new StringContent(jGcmData.ToString(), Encoding.Default, "application/json"))
.ContinueWith(response =>
{
Console.WriteLine(response);
Console.WriteLine("Message sent: check the client device notification tray.");
}));
}
}
catch (Exception e)
{
Console.WriteLine("Unable to send GCM message:");
Console.Error.WriteLine(e.StackTrace);
}
}
}
}
Here is response from server
Id = 13, Status = RanToCompletion, Method = "{null}", Result = "StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:\r\n{\r\n X-Content-Type-Options: nosniff\r\n X-Frame-Options: SAMEORIGIN\r\n X-XSS-Protection: 1; mode=block\r\n Alt-Svc: quic=\":443\"; ma=2592000; v=\"36,35,34,33,32\"\r\n Vary: Accept-Encoding\r\n Transfer-Encoding: chunked\r\n Accept-Ranges: none\r\n Cache-Control: max-age=0, private\r\n Date: Tue, 25 Oct 2016 05:02:12 GMT\r\n Server: GSE\r\n Content-Type: application/json; charset=UTF-8\r\n Expires: Tue, 25 Oct 2016 05:02:12 GMT\r\n}"
I'm not understanding where I'm wrong.
Please help
Amit Saraf
This links helped me a lot to understand the process of GCM push notifications, you can also use POSTMAN to test the sending of the push notifications:
http://forums.xamarin.com/discussion/comment/217083/#Comment_217083
How to use Push Notifications in Xamarin Forms
http://xamarinhelp.com/push-notifications/
Test them:
https://stackoverflow.com/a/30778643/1207924

Web reference created dynamically

I'm developing android app on Xamarin Android in c#.
Is there any way to change dynamically URL of SOAP web service? I want to store url in some kind of config file but I have no idea how do it.
correct me, if i'm wrong
but the second constructor of an xamarin - soap webservice class has a property for URL.
Here's an example of my webservice:
public partial class Service : System.Web.Services.Protocols.SoapHttpClientProtocol
{
public Service()
{
this.Url = "http://xxx/service.asmx";
}
public Service(string url)
{
this.Url = url;
}
}
you've added the webreference in xamarin and then use your webservice - instance.
Just call the second constructor and give them an other url as source.
You could manually create your required connection using Channelfactory that changes as it needs to. You'll need the proper connections in the web.config file.
Here's a way you could set it up.
In your web.config.
<appSettings>
<add key="Identity" value="machineidentity" />
<add key="Binding" value="WSHttpBinding_IService" />
<add key="Endpoint" value="http://Devservice/Service.svc" />
<add key="Identity2" value="localmachine" />
<add key="Binding2" value="WSHttpBinding_IService" />
<add key="Endpoint2" value="http://Devservice/Service.svc" />
<add key="devIdentity" value="localmachine" />
<add key="devBinding" value="WSHttpBinding_IService" />
<add key="devEndpoint" value="http://Devservice/Service.svc" />
</appSettings>
C# code
a configuration class to hold values from the web.config
public static Dictionary<int, Connections> EndpointConnections = new Dictionary<int, Connections>
{
{1, new Connections(){Identity = ConfigurationManager.AppSettings["Identity"],Binding = ConfigurationManager.AppSettings["Binding"], Endpoint = ConfigurationManager.AppSettings["Endpoint"]}},
{2, new Connections(){Identity = ConfigurationManager.AppSettings["Identity2"],Binding = ConfigurationManager.AppSettings["Binding2"], Endpoint = ConfigurationManager.AppSettings["Endpoint2"]}},
{3, new Connections(){Identity = ConfigurationManager.AppSettings["devIdentity"],Binding = ConfigurationManager.AppSettings["devBinding"], Endpoint = ConfigurationManager.AppSettings["devEndpoint"]}},
};
Now a static class for creating the endpoint
private ChannelFactory<IService> SetChannelFactory(int configInput)
{
var identity = EndpointIdentity.CreateDnsIdentity(Configuration.EndpointConnections[configInput].Identity);
var myBinding = new WSHttpBinding(Configuration.EndpointConnections[configInput].Binding);
var myuri = new Uri(Configuration.EndpointConnections[configInput].Endpoint);
var myEndpoint = new EndpointAddress(myuri, identity);
return new ChannelFactory<IService>(myBinding, myEndpoint);
}
Now calling and using the endpoint
public async Task<Result> SomeAction(int selection)
{
IService client = null;
Result result = null;
Response response = null;
using (var myChannelFactory = SetChannelFactory(selection))
{
try
{
client = myChannelFactory.CreateChannel();
response = await client.TheServiceFunction().ConfigureAwait(false);
((ICommunicationObject)client).Close();
}
catch
{
if (client != null)
{
((ICommunicationObject)client).Abort();
return new result ( failure = true);
}
}
}
if (response != null)
{
//Whatever you want to do with the response here
return new result ( failure = false);
}
}

Silverlight not accessing content when using https

I have a SL app that has https and http endpoints. If i access the endpoint on http, then just have a screen which loads an external image
http://somedomain.com/domaimage.jpg
It will work fine.
If i access the SL app on https:// then load the same image it won't even attempt to make the web request for the image.
Why when SL is running on https i doesn't request external content? I have this in my clientaccesspolicy.xml
<?xml version="1.0" encoding="utf-8"?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="*" http-methods="*">
<domain uri="http://*"/>
<domain uri="https://*"/>
</allow-from>
<grant-to>
<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
and this is my crossdomain.xml
<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="*" />
</cross-domain-policy>
Thanks
Steve
Now using an image proxy to access external content, if it helps anyone
ImageProxy.ashx
public class ImageUrlProxy : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
try
{
string url = context.Request.Headers["Url"];
var client = new WebClient();
byte[] imageDataBytes = client.DownloadData(url);
context.Response.ContentType = "application/json;";
context.Response.Write(JsonConvert.SerializeObject(imageDataBytes));
}
catch (Exception)
{
throw;
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
Helper class:
public static class ImageProxyHelper
{
public static void GetImageByProxy(string url, Action<BitmapImage> callback)
{
if (callback == null) return;
var client = new WebClient();
client.DownloadStringCompleted += (sender, args) =>
{
if (args.Error == null)
{
var buffer = JsonConvert.DeserializeObject<byte[]>(args.Result);
var im = new BitmapImage() { CreateOptions = BitmapCreateOptions.None };
im.SetSource(new MemoryStream(buffer));
callback(im);
}
};
client.Headers["Url"] = url;
client.DownloadStringAsync(UrlBuilder("ImageUrlProxy.ashx"));
}
public static Uri UrlBuilder(string fragment)
{
var uriBuilder = new UriBuilder(Application.Current.Host.Source.Scheme,
Application.Current.Host.Source.Host,
Application.Current.Host.Source.Port, fragment);
return uriBuilder.Uri;
}
}
Then from silverlight:
ImageProxyHelper.GetImageByProxy("http://externaldomain.com/image.jpg", p=>{
//Do something here
})
This can be extended to return any external content ^^
You are having the same problem as this question
Https and http Image URL Not loading in silverlight
It is down to cross scheme calls in silverlight

Categories