Resolving FileNotFoundException when using Simple.OData.Client in iOS applications

Several users of Simple.OData.Client 4.0 pre-release reported about an error when using the library on iOS platform. An attempt to send an OData request resulted in FileNotFoundException with the error message about the V3 or V4 adapter, e.g.:

System.IO.FileNotFoundException: Could not load file or assembly 'Simple.OData.Client.V3.Adapter' or one of its dependencies.

This error occurs only on iOS platform, and it is caused by application size optimization performed by the iOS linker. The linker scans applications dependencies and strips out all unused assemblies. Or should I say – assemblies it suspects to be unused. To reduce memory footprint, Simple.OData.Client 4.0 loads only assemblies that are required by the selected version of OData protocol, and the root adapter assembly is loaded by reflection making the iOS linker believe that it’s unused.

This is in fact well-documented behavior, and there are several workarounds. Some of them requires marking code to be preserved with special attributes, but Simple.OData.Client is a packaged as a portable class library, so it can’t have dependencies on platform-specific definitions. An alternative is to include in the main application assembly a single line of code referencing the OData adapter assembly. Here’s how you do it if your application uses OData services over V3 protocol:

Simple.OData.Client.V3Adapter().Reference();

And of the code for V4 protocol is similar:

Simple.OData.Client.V3Adapter().Reference();

Note that this code does nothing. Absolutely nothing. So you can place it anywhere within the iOS application assembly. And it’s only iOS apps that need it. Android, Windows Phone and desktop applications will run fine without an explicit adapter reference.

Advertisements

2 thoughts on “Resolving FileNotFoundException when using Simple.OData.Client in iOS applications

  1. I am posting here, maybe you will have some tip or suggestion. I am using (V3) your great library šŸ™‚ in one Xamarin iOS project.

    Everything goes well for the first two linker options (Do not link and Link SDK assemblies only). I have Simple.OData.Client.V3Adapter.Reference (); in my AppDelegate to avoid linker stripping the code.

    However, I have trouble using it with third linker options: Link all assemblies.
    Maybe the linker stripped some members from some other dependent assembly (e.g. Micrsoft.Data.OData)

    I get the following exception:
    IUnable to load OData adapter from assembly Simple.OData.Client.V3.Adapter —> System.ArgumentNullException: Argument cannot be null. Parameter name: type at System.Reflection.IntrospectionExtensions.GetTypeInfo (System.Type type) [0x0000c] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Reflection/IntrospectionExtensions.cs:38 at Simple.OData.Client.Extensions.TypeExtensions.GetDeclaredConstructors (System.Type type) [0x00000] in :0 at Simple.OData.Client.AdapterFactory.LoadAdapter (System.String adapterAssemblyName, System.String adapterTypeName, System.Object[] ctorParams) [0x00000] in :0 — End of inner exception stack trace — at Simple.OData.Client.AdapterFactory.LoadAdapter (System.String adapterAssemblyName, System.String adapterTypeName, System.Object[] ctorParams) [0x00000] in :0 at Simple.OData.Client.AdapterFactory+c__DisplayClass18.b__16 () [0x00000] in :0 at Simple.OData.Client.AdapterFactory+d__0.MoveNext () [0x00000] in :0 — End of stack trace from previous location where exception was thrown — at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000b] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Runtime.ExceptionServices/ExceptionDispatchInfo.cs:62 at System.Runtime.CompilerServices.TaskAwaiter`1[Simple.OData.Client.IODataAdapter].GetResult () [0x00034] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Runtime.CompilerServices/TaskAwaiter_T.cs:59 at Simple.OData.Client.Session+d__c.MoveNext () [0x00000] in :0 — End of stack trace from previous location where exception was thrown — at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000b] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Runtime.ExceptionServices/ExceptionDispatchInfo.cs:62 at System.Runtime.CompilerServices.TaskAwaiter`1[Simple.OData.Client.IODataAdapter].GetResult () [0x00034] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Runtime.CompilerServices/TaskAwaiter_T.cs:59 at Simple.OData.Client.ODataClient+d__b6.MoveNext () [0x00000] in :0 } System.InvalidOperationException

    Here is the stack trace:
    at System.Threading.Tasks.Task`1[System.Collections.Generic.IEnumerable`1[System.Collections.Generic.IDictionary`2[System.String,System.Object]]].get_Result () [0x0003c] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Threading.Tasks/Task_T.cs:52
    at Simple.OData.Client.FluentClientBase`1+c__DisplayClass4[Ptix.Entities.Show].b__3 (System.Threading.Tasks.Task`1 x) [0x00000] in :0
    at System.Threading.Tasks.TaskActionInvoker+FuncTaskInvoke`2[System.Collections.Generic.IEnumerable`1[System.Collections.Generic.IDictionary`2[System.String,System.Object]],System.Collections.Generic.IEnumerable`1[System.Collections.Generic.IDictionary`2[System.String,System.Object]]].Invoke (System.Threading.Tasks.Task owner, System.Object state, System.Threading.Tasks.Task context) [0x00000] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Threading.Tasks/TaskActionInvoker.cs:330
    at System.Threading.Tasks.Task.InnerInvoke () [0x00019] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Threading.Tasks/Task.cs:546
    at System.Threading.Tasks.Task.ThreadStart () [0x000d0] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Threading.Tasks/Task.cs:438

    Thanks in advance

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s