Portable class library object properties cannot be evaluated - xamarin

I have a problem serializing pcl class object because the class objects property is cannot be evaluated. The structure of my solution is having three projects -
Xamarin.Android, reference Services, and Dto
PCL (for Services), reference Dto (target frameworks: .Net Framework 4.5, ASP.Net Core 1.0, Windows 8, Windows Phone 8.1, Xamarin.Android, Xamarin.iOS, Xamarin.iOS(Classic)
PCL (for Dto)) (target frameworks: .Net Framework 4.5, ASP.Net Core 1.0, Windows 8, Windows Phone 8.1, Xamarin.Android, Xamarin.iOS, Xamarin.iOS(Classic)
I have one method in my service class like -
public async Task<HttpResponseMessage> SignIn(string username, string password)
{
var user = new Dto.UserLogin(username, password);
var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(user);
var content = new StringContent(serialize);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
HttpResponseMessage response = null;
using (var client = GetClient("{urlhere}", username, "POST"))
{
response = await client.PostAsync("api/{methodname}", content);
}
return response;
}
The code above does not throw error and can instantiate the "user" variable. However the problem was that when the serialization line happens, it serialize nothing. It seems like the "user" object is cannot access or show the two properties "Email" and "Password". But I can access them in debug using "user.Email". I've attached a screenshot of it.
Email and Password properties are public.
Thanks,
Marvin

The comment from #Jack helps me to figure out the culprit. In Xamarin.Android property settings->Android options->linker, currently it is set to "SDK and User assemblies". I changed it to "SDK Assemblies Only" and this solved the problem.

Related

Xamarin.Form HttpClient for WebAPI failed in iOS

I'm creating Xamarin.Forms for Android and iOS using WebAPI as the web service. The whole thing went well in Android but I hit error in iOS, particularly when doing "JsonConvert.DeserializeObject". Below is the sample code
Model
public class WsObjTest
{
public string name { get; set; }
public string code { get; set; }
public string age { get; set; }
}
WebAPI
[HttpGet]
public WsObjTest HelloWorld()
{
WsObjTest wsObjTtest = new WsObjTest();
wsObjTtest.name = "John Doe";
wsObjTtest.code = "ABC123";
wsObjTtest.age = "18";
return wsObjTtest ;
}
In my Xamarin.Forms, this is how I call and deserialize the response
HttpClient client = new HttpClient();
var response = await client.GetStringAsync(apiURL.Replace("##action##", "HelloWorld"));
return JsonConvert.DeserializeObject<WsObjTest>(response); //ERROR HERE
I got the response as below, but error thrown at the return statement.
"{\"code\":\"ABC123\",\"name\":\"John Doe\",\"age\":\"18\"}"
The error message is below
Unhandled Exception:
System.MemberAccessException: Cannot create an abstract class:
System.Reflection.Emit.DynamicMethod occurred
I think it's because iOS doesn't support JIT compilation or dynamic methods of some sort? May I know if there is anyway to overcome this error? Thanks.
Based on https://learn.microsoft.com/en-us/xamarin/ios/internals/limitations, it is not possible to use any facilities that require code generation at runtime in Xamarin.iOS because code on the iPhone is statically compiled ahead of time instead of being compiled on demand by a JIT compiler.
What I have to do now is read and create the object manually as below. Should anybody got better solution please share with me.
HttpClient client = new HttpClient();
var response = await client.GetStringAsync(apiURL.Replace("##action##", "HelloWorld"));
JObject jObject = (JObject) JsonConvert.DeserializeObject(response);
WsObjTest wsObjTest = new WsObjTest();
wsObjParent.name = jObject["name"].ToString();
wsObjParent.code = jObject["code"].ToString();
wsObjParent.age = jObject["age"].ToString();
return wsObjTest;
Extracted from the link
Since the iOS kernel prevents an
application from generating code dynamically, Xamarin.iOS does not
support any form of dynamic code generation. These include:
The System.Reflection.Emit is not available.
No support for
System.Runtime.Remoting.
No support for creating types dynamically (no
Type.GetType ("MyType`1")), although looking up existing types
(Type.GetType ("System.String") for example, works just fine).
Reverse
callbacks must be registered with the runtime at compile time.
So the System.Reflection.Emit thus the error that I received.

Xamarin .Net Core HttpClientHandler Method Not Implemented(VS for Mac)

I am writing a .net core(Standard 1.6) library that connects to my WebAPI. The WebApi requires a client certificate.
The .net core library is something being called from a Xamarin iOS app.
I cannot for the life of me send an HTTP request with a Client Certificate header.
I can use the library and post to the API with a client certificate from Visual Studio 2017 on a windows machine.
When I move the same project into my Xamarin iOS app using VS for Mac I get:
"Method Not Implemented" when setting the SslProtocol or adding the client certificate:
var handler = new HttpClientHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.SslProtocols = SslProtocols.Tls12;
handler.ClientCertificates.Add(new X509Certificate2(certificate));
Relevant libraries:
using System.Net;
using System.Net.Http;
using System.Security;
using System.Security.Cryptography.X509Certificates;
Any help would be greatly appreciated.
Alright, this took me quite a while but i was able to send a client certificate in a web request to use for client auth on our server.
First, as awesome as Xamarin and .netCore are, they are missing alot of the methods .net developers are used to. I was not able to build a crossplatform request that would work on both Android and ios such as the HttpWebRequest.
For ios, i created a custom class that inherits from:NSUrlConnectionDataDelegate
I then override the:
public override void WillSendRequestForAuthenticationChallenge(NSUrlConnection
connection, NSUrlAuthenticationChallenge challenge)
{
byte[] cert = System.IO.File.ReadAllBytes("clientCertificate.pfx");
NSUrlCredential credential = iSecurity.ImportPK12File(cert, "certPassword");
challenge.Sender.UseCredential(credential, challenge);
}
I then created a class that returns the credential:
//cert is a byte array of a .pfx file included in the resource file
//iSecurity Custom class
NSUrlCredential credential = iSecurity.ImportPK12File(cert, "certpassword");
public static NSUrlCredential ImportPK12File(byte[] fileBytes, string passPhrase)
{
var cert = new X509Certificate2(fileBytes, passPhrase);
var options = NSDictionary.FromObjectAndKey(NSObject.FromObject(passPhrase), SecImportExport.Passphrase);
NSDictionary[] importStatus;
SecStatusCode statusCode = SecImportExport.ImportPkcs12(fileBytes, options, out importStatus);
if(statusCode != SecStatusCode.Success){
throw new Exception("Error importing certificate. ");
}
NSObject obj = importStatus[0]["trust"];
IntPtr secTrustRef = obj.Handle;
var identityHandle = importStatus[0][SecImportExport.Identity];
var identity = new SecIdentity(identityHandle.Handle);
var certificate = new SecCertificate(cert.GetRawCertData());
SecCertificate[] certificates = { certificate };
return NSUrlCredential.FromIdentityCertificatesPersistance(identity, certificates, NSUrlCredentialPersistence.ForSession);
}
You may also be able to override this method and send the creds:
public override void ReceivedAuthenticationChallenge(NSUrlConnection connection, NSUrlAuthenticationChallenge challenge)
{
base.ReceivedAuthenticationChallenge(connection, challenge);
}
And i may move it to there but in order to fire this off you create the delegate of your class that inherits from :NSUrlConnectionDataDelegate
and add this to your connection. Any request fired through this connection will override the method and pass the certificate.

ServiceStack Caching Working in VS2012, but not in Xamarin Studio 4.2.3 (build 60)

My application makes an AJAX call to the route /{Lang}/cook to retrieve an rendered Razor partial.
In VS2012 via Cassini, I am able to get a response;
However, in Xamarin 4.2.3 (build 60), I get the following error:
Failed to load resource: the server responded with a status of 405 (NotImplementedException)
http://127.0.0.1:8080/en-us/cook
Any ideas why the route works in one IDE, but not the other?
I am using Service Stack 4.0.12.0, with In-Memory caching.
The system is being run in free/evaluation mode.
Here is a service method that uses caching:
Inside public class ScenarioService: Service
[DefaultView("cook")]
public object Get(CookScenario request)
{
var cacheKey = GetCacheKey ("cook", request.Lang);
return base.Request.ToOptimizedResultUsingCache (base.Cache, cacheKey, () => {
CookScenarioResponse response = LoadJson<CookScenarioResponse>(request.Lang, "cook");
return response;
});
}
Inside AppHost.cs
public override void Configure(Funq.Container container)
{
//Set JSON web services to return idiomatic JSON camelCase properties
ServiceStack.Text.JsConfig.EmitCamelCaseNames = true;
//Configure User Defined REST Paths
container.Register<ICacheClient>(new MemoryCacheClient());
this.GlobalRequestFilters.Add((request, response, requestDto) =>
{
var localizedReq = requestDto as LocalizedRequest;
if (localizedReq != null)
{
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentUICulture = new CultureInfo(localizedReq.Lang);
}
});
Plugins.Add(new RazorFormat());
}
EDIT:
I tried removing the ToOptimizedResultUsingCaching and the service for "/en-us/cook" worked fine; so, the issue is definitely an issue with the ToOptimizedResultUsingCaching in Service Stack 4.0.12.0 on Xamarin Studio 4.2.3 (build 60) on a Mac OS 10.7.5.
Here is the mono version info:
Mono JIT compiler version 3.2.6 ((no/9b58377 Thu Jan 16 17:49:56 EST 2014)
Resolution 3/27/2014 1PM PST
After I grabbed the pre-release version (4.0.16) of ServiceStack I was able to confirm that in-memory caching now works on Xamarin 4.2.3 (build 60) against my Macbook pro laptop (OSX 10.7.5).
Thanks again for the help!
I believe the error you are seeing is a shortcoming of Mono, and the XSP/fastcgi-server-4 host which is used by Xamarin Studio.
I previously experience the same problem with ToOptimizedResult/ToOptimizedResultUsingCache methods not working because they rely on a call to System.Web.HttpContextWrapper.GetService which has not been implemented in Mono.
See here for the relevant Mono source code:
public class HttpContextWrapper : HttpContextBase
{
...
[MonoTODO]
public override object GetService (Type serviceType)
{
throw new NotImplementedException ();
}
}
I found the only way to work around this issue with Mono was to use a Self Hosted ServiceStack application because it uses System.Net.HttpListener which does not suffer from this issue. See my previous answer on this issue which describes this in more detail.
Fix:
A commit to ServiceStack has been made to address this issue, and it will be fixed in version 4.0.16

Windows Phone using accept-encoding gzip compression in webclient

I need to post data to server, and get compressed data back from it.
I am using windows phone 7 sdk.
I read that it can be done using SharpGIS or Coding4Fun toolkit.
They use WebClient (AFAIK).
can anyone help me?
Here's what I need to do-
Post data(XML) to url
Get compressed data (only GZip supported by server) in the form of xml string/stream
deserialise the xml data received
and the methods should be awaitable.
When I had to do this in wp7, I
Created a Portable Class Library project within my solution
Nuget the HTTP client library at https://www.nuget.org/packages/Microsoft.Net.Http (Install-Package Microsoft.Net.Http)
Nuget http://www.nuget.org/packages/Microsoft.Bcl.Async/ (Install-Package Microsoft.Bcl.Async ) and add to your PCL and UI solution
With in the portable class library
public class PostData
{
public async Task<T> TestMe<T>(XElement xml)
{
var client = new HttpClient(new HttpClientHandler
{
AutomaticDecompression = DecompressionMethods.GZip
| DecompressionMethods.Deflate
});
var response = await client.PostAsync("https://requestUri", CreateStringContent(xml));
var responseString = await response.RequestMessage.Content.ReadAsStringAsync();
//var responseStream = await response.RequestMessage.Content.ReadAsStreamAsync();
//var responseByte = await response.RequestMessage.Content.ReadAsByteArrayAsync();
return JsonConvert.DeserializeObject<T>(responseString);
}
private HttpContent CreateStringContent(XElement xml)
{
return new StringContent(xml.ToString(), System.Text.Encoding.UTF8, "application/xml");
}
}
WebClient and HttpWebRequest for C4F toolkit are supported. HttpClient doesn't exist without http client library currently in WP.
I don't use Windows 8, which means Windows Phone SDK is only on VS 2010, which doesn't support the Microsoft HttpClient.
There's a NuGet package Delay.GZipWebClient written by an MS dev that adds simple support for it. So far it's worked like a charm.
http://blogs.msdn.com/b/delay/archive/2012/04/19/quot-if-i-have-seen-further-it-is-by-standing-on-the-shoulders-of-giants-quot-an-alternate-implementation-of-http-gzip-decompression-for-windows-phone.aspx

Adding Windows Phone 8 Tile functionality to Windows Phone OS 7.1 app

I'm trying to support the new Windows Phone tile functionality in my existing Windows Phone OS 7.1 application, using the documentation from MSDN. However, I can't seem to create an IconicTile through reflection as it keeps giving me NullReferenceExceptions and AmbiguousMatchExceptions. Here is the code I am using:
public static void CreateIconicTile(Uri tileId, string title, int count, string wideContent1, string wideContent2, string wideContent3, Uri smallIconImage, Uri iconImage, Color backgroundColor)
{
// Get the new IconicTileData type.
Type iconicTileDataType = Type.GetType("Microsoft.Phone.Shell.IconicTileData, Microsoft.Phone");
// Get the ShellTile type so we can call the new version of "Update" that takes the new Tile templates.
Type shellTileType = Type.GetType("Microsoft.Phone.Shell.ShellTile, Microsoft.Phone");
// Get the constructor for the new IconicTileData class and assign it to our variable to hold the Tile properties.
StandardTileData CreateTileData = new StandardTileData();
// Set the properties.
SetProperty(CreateTileData, "Count", count);
SetProperty(CreateTileData, "WideContent1", wideContent1);
SetProperty(CreateTileData, "WideContent2", wideContent2);
SetProperty(CreateTileData, "WideContent3", wideContent3);
SetProperty(CreateTileData, "SmallIconImage", smallIconImage);
SetProperty(CreateTileData, "IconImage", iconImage);
SetProperty(CreateTileData, "BackgroundColor", backgroundColor);
// Invoke the new version of ShellTile.Create.
shellTileType.GetMethod("Create").Invoke(null, new Object[] { tileId, CreateTileData });
}
I also tried creating the tile using the Windows Phone OS 7.1 way (ShellTile.Create(...)) and then calling the UpdateIconicTile method via reflection as described in the MSDN documentation. But that didn't work either.
Any help would be greatly appreciated. Thanks!
EDIT: Just to clarify, I am checking the platform version to ensure this code only runs on Windows Phone 8 devices and I have added the necessary code to my manifest.
RESOLVED: Thanks to the answer given by Martin Suchan below, I was able to solve this problem. The problem was with my call to Invoke(...) missing some properties. Here is the new line I am using to actually create the tile:
shellTileType.GetMethod("Create", new Type[] { typeof(Uri), typeof(ShellTileData), typeof(bool) }).Invoke(null, new Object[] { tileId, CreateTileData, true });
Have you tried the library Mangopollo, that contains working wrapper for creation new tiles in WP7.1 apps when running on WP8?
http://mangopollo.codeplex.com/
You have to make sure that reflection is enabled across the code.
Iconic Tiles are only available for windows phone 8 therefore you can only put the code into a windows phone 7.1 project if you check the version
private static Version TargetedVersion = new Version(8, 0);
public static bool IsTargetedVersion {get{
return Environment.OSVersion.Version >= TargetedVersion;}}
Now see if the bool IsTargetedVersion is true. Basically,
if(IsTargetedVersion){
//iconic tile code
}
Thus only when a windows phone with compatible features (i.e. an wp8) runs your app then it will work.

Resources