A következő címkéjű bejegyzések mutatása: XAMARIN. Összes bejegyzés megjelenítése
A következő címkéjű bejegyzések mutatása: XAMARIN. Összes bejegyzés megjelenítése

2018. május 27., vasárnap

XAMARIN és a WCF

A ritka kivételektől eltekintve szinte mindegyik mobil alkalmazás kommunikál valamilyen backend rendszerrel, most csupán a Windows  Communication Foundation (WCF) vonalra térnék ki.

Sok helyen lehet találkozni olyannal, hogy nem működik a WCF Xamarin alatt, pedig csupán néhány korlátozással kell együtt élni a cél elérése érdekében.

Ezen a linken elérhető egy követhető leírás Xamarinhoz arról, hogyan kell összekötni egy WCF-es kiszolgálóval. Ehhez tennék kiegészítést néhány speciális esetet megvizsgálva.

Korlátozások

  • Nincs XAML konfig
A "hagyományos" XML alapú konfigurációs fájlokkal tényleg nem lehet megvalósítani, mivel nem lehet csak úgy odatenni az indítófájl mellé. Másfelől .NET C# alatt, - hasonlóan a WPF UI vezérlőkhöz - ami konfig fájlban XAML-lel leírható, az C# kóddal is. Ezt használja ki a fentebb linkelt tutoriál is.

  • Nincs NetTCPBinding
Fontos megjegyezni, hogy mobilon nem létezik a NetTCPBinding, csak valamilyen *HttpBinding típust lehet használni.

  • Nincs EndpointBehaviors
PCL készítésekor egy WCF kliensben a Behavior helyett az EndpointBehaviort kell használni, ami Windows RT-n még elfut, de Android és iOS rendszereken a MONO alatt NotImplementedExceptionnel elszáll. Szerencsére reflectionnel kinyerhető a megoldás:
//client.Endpoint.EndpointBehaviors.Add(new EndpointBehavior());

//client is of type System.ServiceModel.ClientBase<T>
var prop = client.Endpoint.GetType()
                 .GetTypeInfo()
                 .GetDeclaredProperty("Behaviors");
var obj = (KeyedCollection<Type, IEndpointBehavior>)prop
                 .GetValue(client.Endpoint);
obj.Add(new EndpointBehavior());

Ugyanez a helyzet a MessageInspectorral is:
//clientRuntime.ClientMessageInspectors.Add(new MessageInspector());

var prop = clientRuntime.GetType()
                        .GetTypeInfo()
                        .GetDeclaredProperty("MessageInspectors");
var obj = (ICollection<IClientMessageInspector>)prop
                        .GetValue(clientRuntime);
obj.Add(new MessageInspector());

Wrapper a WCF hívás körül

Korábban már írtam arról, hogyan célszerű felkészülni arra, ha a WCF kliens hívása kezeletlen hibára fut. Ilyenkor nem szabad a Close()-t ráhívni, mint ahogy azt teszi alapértelmezetten a USING, helyette Abort() kell.

Async/await és a WCF

Xamarin alatt is használhatók az async/await kulcsszavak, amik tökéletesen illeszkednek az aszinkron WCF hívások köré. Bővebb leírás itt található.

public class WcfServiceWrapper:IWcfServiceWrapper
{
    private IWcfService _wcfService;

    public WcfServiceWrapper(IWcfService wcfService)
    {
        if (wcfService == null) throw new ArgumentNullException("wcfService");

        _wcfService = wcfService;
    }

    public async Task<string> GetDataAsync(int number)
    {
        return await new TaskFactory()
          .FromAsync<int,string>(
            _wcfService.BeginGetData, 
            _wcfService.EndGetData, 
            number, 
            null, 
            TaskCreationOptions.None
          );
    }
}

.NET Portable Assembly


Ha esetleg bármi miatt szeretnénk hozzáadni mobilon is használható .NET portable assembly-t, akkor azok itt találhatók:
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.5\

Generált proxy és az IExtensibleDataObject


A WCF által publikált WSDL alapján le lehet generálni a hálózaton keresztül utazó osztályokat. Amennyiben a DataContractSerializert használjuk szerver oldalon, akkor ráteszi az IExtensibleDataObject interfészt és a hozzátartozó ExtensionDataObject tulajdonságot ezen generált osztályokra. Önmagában nem lenne baj, hiszen a System.Runtime.Serialization.dll-ben elérhető ez az interfész és osztály, van belőle portable DLL is, gondolhatnánk, hogy majd hozzáadjuk a PCL projekthez és készen vagyunk. Nos, ez az út nem járható, nem engedi hozzáadni azzal az üzenettel, hogy már referálja a sajátját. A probléma az, hogy abban viszont nincsenek benne ezek. 

1) Egyik megoldás lehet, hogy a kiszolgáló oldalon a ServiceContract attribútumban vagy akár magában a DataContractSerializerben bekapcsoljuk, hogy IgnoreExtensionDataObject. Viszont ezek a nevüknek megfelelően csak annyit csinálnak, hogy figyelembe kell-e venni az ExtensionDataObjectet vagy sem, de továbbra is megmaradnak az osztályokban. Elvileg a platformspecifikus projekthez már hozzá lehet adni ezt a dll-t, és utána működhet valahogy a DependencyService-en keresztül, de ezt a vonalat nem próbáltam ki.

2) Ha biztosan tudjuk, hogy egyáltalán nem használjuk semmire az ExtensionDataObjectet, akkor egy-egy üres osztállyal és interfésszel könnyedén orvosolható a helyzet:
 public interface IExtensibleDataObject { ExtensionData { get; set; } }  public sealed class ExtensionDataObject {}

2017. június 24., szombat

XAMARIN app nem indul eszközön debugban

Visual Studio-val szerettem volna egy XAMARIN.FORMS alkalmazást Android telefonon tesztelni, de az alábbi hibaüzenet fogadott:

The application could not be started. Ensure that the application has been installed to the target device and has a launchable activity (MainLauncher = true).
Additionally, check Build->Configuration Manager to ensure this project is set to Deploy for this configuration.

Attól függetlenül, hogy sikeresen lefordult és a deploy során sem panaszkodott semmire, mégsem találta meg a telefonon az alkalmazást. Az eszköz főmenüjét megnézve, valóban nem volt indítóikon. A helyzetet tovább bonyolította, hogy nem mindegyik eszköz reagált így, volt, amelyiken ment. Ráadásul a problémások másik gépen jól működtek.

A vizsgálódás során kipróbáltam, hogy ha másik csomagazonosítót állítok be, akkor mit reagál. Az új azonosítóval gond nélkül elindult mindegyik eszközön.

A problémás eszközökön mindegyiknél megtaláltam az Alkalmazások listájában a régi csomagazonosítóval az appot, tehát valamilyen formában már telepítve volt egy verzió. Végül összeállt a kép: a Visual Studio-val történő telepítés során - számomra ismeretlen célból - valamilyen egyedi azonosítót is generál az alkalmazásba - talán a Fast Deploymenttel lehet összefüggésben -, ami megakadályozza, hogy egy másik VS rá tudjon frissíteni a már telepített verzióra.

A megoldás az volt, hogy kézzel el kellett távolítani a korábbi verziót, ami a másik VS-től származott és azt követően mindegyik készüléken működött.

2017. június 15., csütörtök

Visual Studio 2015 Crossplatform - hiányzó Xaml Page template

Visual Studio 2015 és Xamarin páros telepítését követően találkoztam azzal a jelenséggel, hogy hiába adtam a projekthez bármilyen új XAML Page vezérlőt, minden esetben csak egy C# fájlt készített, de XAML-t sosem. A probléma feloldásához a hiányzó sablonfájlt át kellett másolni a Xamarin alól a VS ItemTemplates mappájába.

Innen kell átmásolni:
C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\Extensions\Xamarin\Xamarin\
<verzió>\T\IT\Cross-Platform\Code\XamlPage.zip

Ide:
C:\Users\<felhasználó>\Documents\Visual Studio 2015\Templates\ItemTemplates\
Visual C#\XamlPage.zip

Ezt követően a "Cross-Platform" szekcióban lehetett kiválasztani a "Forms Xaml Page" elemet.