Vytvorenie InfoPath Formulára odosielajúceho súbor cez webovú službu - krok za krokom

Publikoval Michal Kočí dňa 17.4.2007 o 01:23 v kategórii InfoPath

V tomto príspevku ukážem krok za krokom:

  • Ako vytvoriť InfoPath formulár
  • Ako vytvoriť dátové spojenie
  • Ako nakonfigurovať formulár na odoslanie dát webovej službe
  • Ako sa dá na formulár umiestniť prvok umožňujúci pridanie súboru
  • Ako spracovať priložený súbor
  • Ako pridať programový kód

V InfoPath vytvoríte formulár veľmi jednoducho - z menu File vyberiete možnosť Design a Form Template. Vyberiete si, že chcete začať s prázdnym formulárom:

Keďže sa chcem sústrediť na demonštráciu odoslania súboru cez webovú službu, tak nebudem formulár zbytočne komplikovať inými ovládacími prvkami a na formulár vložím iba prvok File Attachment:

Ak sa teraz pozrieme na hlavný dátový zdroj, uvidíme že nám v ňom pribudol jeden element - field1. Tento si premenujeme na FileControl (jednoducho na neho dvojkliknite a v zobrazenom dialógu zmeňte jeho názov):

Ak sa pozriete na jeho vlastnosti, potom uvidíte, akého typu je tento element:

Element FileConteol je Picture or File Attachment (base64). Keďže všetky dáta formulára sú pri jeho uložení ukladané do XML súboru, musí byť každý element reprezentovaný ako string. Preto ak chceme mať v XML binárne dáta, je výhodné ich prekódovať na base64 string, čo za nás spraví samotný InfoPath.

Až potiaľto je všetko bez problémov, ak chcete aby súbor bol len obsahom formulára, tak Vaša práca v tomto momente viac menej skončila.

Ak však chcete poslať súbor ako parameter webovej službe, čaká Vás jeden malý zádrhel. A to, že v elemente budete mať síce obsah súboru zakódovaný base64 ale nie iba súbor. InfoPath si totiž do tohto elementu uloží aj jeho názov, teda pred samotným obsahom súboru sa nachádzajú aj akési metadáta. Našťastie sú tieto zdokumentované a nie je problém si napísať funkciu, ktorá z obsahu vyextrahuje samotný súbor a aj názov súboru. Tieto potom môžete poslať webovej službe, ktorá môže so súborom ďalej naložiť podla potreby.

Takže ak si predstavíme jednoduchú metódu webovej služby, ktorá súbor uloží na disk c, tak táto by mohla vyzerať nasledovne:

[WebMethod]
public void SaveFile(string name, byte[] content)
{
    FileStream fs;
    fs = File.Open("c:\\" + name, FileMode.Create, FileAccess.Write, FileShare.Read);
    try
    {
        fs.Write(content, 0, content.Length);
    }
    finally
    {
        fs.Close();
    }
}

Zostáva ešte pripraviť formulár na odosielanie dát webovej službe. Najjednoduchšie je, ak máte pre každý parameter webovej služby pripravený jeden element v hlavnom dátovom zdroji a jednoducho ich namapujete. Preto si do dátového zdroja pridajte dva elementy:

  • FileName typu string
  • FileContent typu base64

Nastáva otázka kedy a ako vyextrahovať obsah a názov súboru a naplniť ich do pripravených elementov. Jednoducho vtedy, keď sa zmení hodnota elementu FileControl. Treba teda pridať ošetrenie tejto udalosti.

Ešte pred tým, než začnete programovať sa presvedčte v menu Tools - Form Options že máte na záložke Programming vybratý Váš oblúbený programovací jazyk (C# alebo Visual Basic):

Ošetrenie udalosti jednoducho spravíte tak, že kliknete pravým tlačidlom na element FileControl a z kontextového menu Programming vyberiete položku Changed Event:

InfoPath 2007 za Vás vygeneruje kód, ktorý zabezpečí ošetrenie požadovanej udalosti:

public void InternalStartup()
{
    EventManager.XmlEvents["/my:myFields/my:FileControl"].Changed +=
        new XmlChangedEventHandler(FileControl_Changed);
}

A Vy už musíte iba napísať telo tejto metódy. Takže, čo v tele treba spraviť. Treba aby ste získali prístup ku všetkým trom elementom, z jedného načítate dáta a do zvyšných dvoch dáta budete zapisovať. Ku všetkým trom budeme pristupovať ako k objektom typu XPathNavigator:

public void FileControl_Changed(object sender, XmlEventArgs e)
{
    if (e.Operation == XmlOperation.ValueChange)
    {
        XPathNavigator doc = MainDataSource.CreateNavigator();
        XPathNavigator fileControl = 
            doc.SelectSingleNode("/my:myFields/my:FileControl", NamespaceManager);
        XPathNavigator fileName = 
            doc.SelectSingleNode("/my:myFields/my:FileName", NamespaceManager);
        XPathNavigator fileContent = 
            doc.SelectSingleNode("/my:myFields/my:FileContent", NamespaceManager);

        ProcessFile(fileControl, fileName, fileContent);
    }
}

Všimnite si, že kód chceme vykonať len ak sa zmenila hodnota XML elementu (XmlOperation.ValueChanged). Z tejto metódy voláme metódu ProcessFile, ktorej predáme odkazy na všetky tri elementy. Táto metóda zistí hodnotu elementu FileControl a pomocou pomocnej metódy ExtractFile vyextrahuje názov a obsah súboru. Tieto dáta zapíše do elementov FileName a FileContent:

private void ProcessFile(XPathNavigator fileControl, XPathNavigator fileName, XPathNavigator fileContent)
{
    string control = fileControl.Value;
    string name;
    byte[] content;

    if (control.Length != 0)
    {
        ExtractFile(control, out name, out content);
        string contentAsString = Convert.ToBase64String(content);

        fileName.SetValue(name);

        if (fileContent.MoveToAttribute("nil", "http://www.w3.org/2001/XMLSchema-instance"))
            fileContent.DeleteSelf();
        fileContent.SetValue(contentAsString);
    }
}

Tu si všimnite jeden malý hack, ktorý je potrebné výkonať. Ak chcete naplniť hodnotu elementu ktorý nie je typu string a môže obsahovať nullovú hodnotu, potom je potrebné odstrániť parameter nil.

Samotná metóda ExtractFile potom pracuje podľa spomenutého popisu obsahu elementu FileControl kedy najskôr zistí dĺžku názvu súboru, tento názov vykopíruje, odstráni z neho ukončovací znak ktorý tento názov vždy obsahuje a nakoniec vyextrahuje samotný obsah súboru:

private void ExtractFile(string originalContent, out string fileName, out byte[] fileContent)
{
    byte[] baAttach = Convert.FromBase64String(originalContent);

    // zistenie dlzky nazvu suboru
    int iFNLength = baAttach[20] * 2;
    byte[] baFileName = new byte[iFNLength];

    // vyextrahovanie nazvu suboru
    for (int i = 0; i < iFNLength; i++)
    {
        baFileName[i] = baAttach[24 + i];
    }
    fileName = System.Text.UnicodeEncoding.Unicode.GetString(baFileName);
    fileName = fileName.Substring(0, fileName.Length - 1);

    // vyextrahovanie obsahu suboru
    fileContent = new byte[baAttach.Length - (24 + iFNLength)];
    for (int i = 0; i < fileContent.Length; ++i)
    {
        fileContent[i] = baAttach[24 + iFNLength + i];
    }
}

No a posledný krok je nastavenie odosielania. V info panely sa prepnite na Data Sources (alebo v menu View vyberte položku Data Source). Kliknite na Manage Data Connections. Je totiž potrebné pridať dátové spojenie - spojenie s webovou službou. V zobrazenom dialógu vidíte všetky dátové spojenia (momentálne žiadne):

Kliknite na Add a vyberte že chcete spojenie ktoré odosiela dáta (submit):

Vyberte si, že chcete odoslať dáta pomocou webovej služby:

Zadajte URL webovej služby:

A nakoniec vyberte ku ktorej metóde sa chcete pripojiť:

A v poslednom dialógu nastavíte mapovanie parametrov na elementy dátového zdroja. Prvý parameter namapujte na element FileName, ak ste postupovali podľa návodu tak Xpath je /my:myFields/my:FileName a druhý nastavte na element FileContent ktorého Xpath je /my:myFields/my:FileContent:

No a na poslednej záložke si pomenujte dátový zdroj podľa Vašej ľubovôle.

Úplne posledný krok je nastavenie formuláru aká činnosť sa má vykonať pri pokuse o submit, čiže pri pokuse o odoslanie dát. Tu chcete nastaviť odoslanie pomocou práve vytvoreného dátového spojenia. Preto v menu Tools vyberte položku Submit Options a v zobrazenom dialógu nastavte, že dáta chcete odoslať webovej službe a vyberte spojenie ktoré ste práve vytvorili:

A je to. Keď sa prepnete do Preview, tak si môžete formulár vyskúšať. Otázky? Žiadne? Výborne, ako som vravel, jednoduché a rýchle. Čo myslíte?

Mohlo by ťa tiež zaujímať

Páčil sa ti príspevok?

Zdieľaj príspevok alebo si ho odlož na neskôr

Sleduj ma

Ak nechceš premeškať príspevky ako je tento, sleduj ma na Twitteri, alebo ak máš RSS čítačku, môžeš sledovať môj RSS kanál.