reede, 15. veebruar 2019

Sertifikaatide tegemine Telia XTee keskkonnaga liitumiseks

XTeele andmeid edastava serveri ühendamiseks Telia turvaserveriga on vaja genereerida sertifikaadid ja parooliga võti, seda saab teha OPENSSL utiliidi kaudu

Windows keskkonnas näiteks https://slproweb.com/products/Win32OpenSSL.html

Käsud on järgmised

Sertifikaadi genereerimine

openssl req -new -newkey rsa:4096 -x509 -sha256 -days 1826 -nodes -out TartuYliopilaskyla.crt -keyout TartuYliopilaskyla.key

-days 1826  määrab kaua päev sertifikaat kehtib
Common Name pane rakenduse URL aadress


TartuYliopilaskyla.crt on siis serveri sertifikaat, mis tuleb saata Teliasse ja paigaldada ka Windows Serveri Trusted Root sertifikaadihoidlasse

Privaatvõtme tegemine, parool jäta meelde, seda läheb importmisel vaja

openssl pkcs12 -export -out personalprivat.pfx -inkey TartuYliopilaskyla.key -in TartuYliopilaskyla.crt



personalprivat.pfx on nüüd parooliga sertifikaat mis paigaldada Windows Serveri Personal sertifikaadihoidlasse. Paigaldamisel küsitakse parooli, mis genereerimisel sai sisestatud.



Kui kõik sobib siis Personal sertifikaadihoidlas olev Certification Path peab olema vigadeta



Selleks, et C# meetodid saaksid seda sertifikaati kasutada tuleb rakenduste kontodele anda ka ligipääsu õigused.

Õiguste andmine rakenduste kontodele


teisipäev, 12. veebruar 2019

Lehekülgede pagineerimine ORACLE-s ühe SELECT lause kasutamisega ainult


Eriti REST rakenduste puhul tuleb sageli pagineerimine teha andmebaasi poolel.

Läbi tuleb teha selleks kaks etappi
1. Saada teade kirjete koguarv
2. Võtta vajalik vahemik välja

ORACLE WITH konstruktsiooni tehes saab selle tehe ühe SELECT lausega ainult, mis juhtudel, kui SELECT lause ise võtab kaua aega annab märgatava ajalise kokkuhoiu

Näide, kus annad ette lehekülje suuruse ja mitmendat lehekülge tahad

SET SERVEROUTPUT ON
DECLARE i_page_size INTEGER;  --lehekülje suurus
i_page_no INTEGER; --mitme lehekülg kuvada
BEGIN
i_page_size:=5;
i_page_no:=2;
FOR ss IN (
 WITH Tu AS
        (  SELECT ROWNUM AS jrk, dde.ID, dde.SUBJECT_ID, dde.OCCUP_NAME
                , CEIL((ROWNUM)/i_page_size) AS PAGE_NUMBER --arvutab lehekülje numbri
            FROM
            (  SELECT ID, SUBJECT_ID, OCCUP_NAME FROM SUB_EMPLOYER ORDER BY OCCUP_NAME DESC ) dde
     )       
     SELECT Tu.jrk, Tu.ID, Tu.SUBJECT_ID, Tu.OCCUP_NAME,Tu.PAGE_NUMBER
       ,(SELECT MAX(Tu.jrk) FROM Tu ) AS kokku_kirjeid
       FROM Tu
         WHERE Tu.PAGE_NUMBER = i_page_no  --pagineerimine
         ORDER BY Tu.jrk)
LOOP
    DBMS_OUTPUT.PUT_LINE ( SS.JRK || ' ' || ss.OCCUP_NAME || ' ' || ss.SUBJECT_ID  || ' ' || ss.kokku_kirjeid);
END LOOP;
END;

WITH konstruktsiooni osa, saab kätte kirje järjekorra numbri ja CEIL funktsiooniga arvutab lehekülje numbri

ROWNUM AS jrk, CEIL((ROWNUM)/i_page_size) AS PAGE_NUMBER
      
 hilisemas välises päringus saab eraldi tulbast kätte ka kirjete koguarvu
(SELECT MAX(Tu.jrk) FROM Tu ) AS kokku_kirjeid



Mõnikord vaja saada lisaks eraldi teada ka kirjete ja lehekülgede koguarv siis kasutab CURSOR-i kuhu lisab ette esimeseks lehekülgede ja ridade koguarvuga rea ning FETCH-ib selle välja enne tagastamist. Esimese rea väljatõmbamisel saad lehekülgede ja kirjete koguarvu teada
o_totalPages:=nvl(ceil(o_totalRows/i_page_size),0); --arvutame lehekülgede arvu
o_totalRows:=nvl(o_totalRows,0); --nvl et saaks ridade puudumisel number 0-i välja



SET SERVEROUTPUT ON
DECLARE i_page_size INTEGER;  --lehekülje suurus
i_page_no INTEGER; --mitmes lehekülg kuvada
o_cursor sys_refcursor;  --siia paneme tulemused
o_totalPages INTEGER; --mitu lehekülge kokku
o_totalRows INTEGER; --mitu rida kokku

v_int integer; --abimuutuja
v_int2 integer; --abimuutuja
v_lehekulg integer; --abimuutuja
v_subject_id varchar2(8000); --abimuutuja
v_occup_name varchar2(8000); --abimuutuja
BEGIN
i_page_size:=5;
i_page_no:=2;

open o_cursor for
 WITH Tu AS
        ( 
        SELECT dde2.jrk, dde2.ID, dde2.SUBJECT_ID, dde2.OCCUP_NAME, dde2.PAGE_NUMBER
        FROM (
        SELECT ROWNUM AS jrk, dde.ID, dde.SUBJECT_ID, dde.OCCUP_NAME
                , CEIL((ROWNUM)/i_page_size) AS PAGE_NUMBER --arvutab lehekülje numbri
            FROM
            (  SELECT ID, SUBJECT_ID, OCCUP_NAME FROM SUB_EMPLOYER ORDER BY OCCUP_NAME DESC ) dde ) dde2
     )       
     SELECT Tu.jrk, Tu.ID, Tu.SUBJECT_ID, Tu.OCCUP_NAME,Tu.PAGE_NUMBER
       ,(SELECT MAX(Tu.jrk) FROM Tu ) AS kokku_kirjeid
       FROM Tu
         WHERE Tu.PAGE_NUMBER = i_page_no  --pagineerimine
       
    UNION --tekitame juurde esimese rea, sellekaudu saab fetch ridade koguarvu teada väljastuseks
        SELECT 0 as jrk, Tu.ID, Tu.SUBJECT_ID, Tu.OCCUP_NAME,Tu.PAGE_NUMBER
       ,(SELECT MAX(Tu.jrk) FROM Tu ) AS kokku_kirjeid FROM Tu WHERE Tu.jrk =1
         ORDER BY 1;  --et 0 as jrk rida esimeseks tuleks, mille FETCH-iga välja võtame
        
    --Esimese rea kursorist võib ära raisata, küsib sealt lehekülgede koguarvu ja kirjete koguarvu
     FETCH o_cursor INTO v_int, v_int2, v_subject_id, v_occup_name, v_lehekulg,o_totalRows;
             o_totalPages:=nvl(ceil(o_totalRows/i_page_size),0); --arvutame lehekülgede arvu
             o_totalRows:=nvl(o_totalRows,0); --nvl et saaks ridade puudumisel number 0-i välja
     IF o_totalRows=0 THEN   --anname tühja kursori välja, kui kirjeid üldse pole, tuleb viga ORA-01002: fetch out of sequence
        CLOSE o_cursor;
        OPEN o_cursor FOR
         SELECT 0 AS jrk , 0 AS ID, '' AS SUBJECT_ID, '' AS OCCUP_NAME, 0 AS PAGE_NUMBER, 0 AS kokku_kirjeid FROM dual;
     END IF;
     DBMS_OUTPUT.PUT_LINE ( 'Kokku kirjeid: ' || o_totalRows  || '   Kokku lehekülgi: ' || o_totalPages);
    
    
     LOOP
          FETCH o_cursor INTO  v_int, v_int2, v_subject_id, v_occup_name, v_lehekulg,o_totalRows;
             EXIT WHEN o_cursor%NOTFOUND;
          DBMS_OUTPUT.PUT_LINE ('Jrk: ' ||  v_int || ' ' || v_occup_name || ' ' || v_subject_id);
     END LOOP;
    
END;

Konstruktsioon 
.. UNION .. WHERE Tu.jrk =1 .. ORDER BY 1  teeb selle, et "tühi rida" mille võib ära visata tekib CURSOR-isse esimeseks, kust loeb välja kirjete ja lehekülgede koguarvu.

Kui kirjeid pole IF o_totalRows=0 THEN siis tekitab tühja üherealise CURSOR-i REST kliendi jaoks juhuks kui REST kliendile ei meeldi, et andmebaasist mitte kui midagi ei tagastata.

esmaspäev, 11. veebruar 2019

Validate of viewstate MAC failed viga IIS HTTPS ühenduse korral

Kui oled IISi peale paigaldanud veebirakenduse ja seadistanud ta ka HTTPS protokolli kasutama siis võib käivitamisel ilmuda viga koos soovitustes antud lingiga


Üks asi mida veel vaadata on web.config failis httpCookies seadistus, millele saab lisada turvalisust tõstvaid atribuute requireSSL="true" ja domain="www.veebileht.ee".
Jälgida tuleb, et domain parameeter langeks kokku veebilehe URL aadressiga. Selle kaudu kontrollitakse, et ViewState tuleb õigelt veebilahelt

pühapäev, 10. veebruar 2019

ASP.NET digiallkirjastamine IIS veebiserveris

Mõnikord siis vaja ka ASP.NET veebirakendusse digiallkirjastamine lisada, üks võimalus siis nii, et teed digidoc4j põhjal Java Spring Boot rakenduse mille käivitad Windows Serveris kui Wrapper teenuse.

Sellest juhendist Windows Service Wrapper täitsa töötab
https://www.baeldung.com/spring-boot-app-as-a-service

Idee siis selline, et näidisrakendust https://github.com/rvillido/digidoc4j-hwcrypto-demo
on muudetud nii, et Java osas toimub signeerimine ja valideerimine aga andmete salvestamine on Java Spring Boot rakendusest välja toodud ja tehakse ASP.NET ja MS SQL SERVER-i sees
https://github.com/open-eid/digidoc4j/wiki/Examples-of-using-it

Java Spring Boot rakendus asub siin, kõigepealt tuleb serverisse Java 1.8 paigaldada
https://github.com/kuidokylm/KampusBdoc

Kui saad selle Windows Service Wrapperi abil paigaldatud siis ava Windows Serveris sirvik ja vaata, mis seal http://localhost:8083 vastu vaatab, peaks tulema selline pilt


Java Spring Boot töötab GET ja POST päringute töötlemisega URL-i pihta, ehk serveri peal
sirviku http://localhost:8083/port päring peaks andma sellise vastuse


Kõik test URL-id leiab  Java @RestController public class TestController-ist


Digiallkirjastamise jaoks tuleb sõlmida SK ID Solutions leping Ajatempliteenuse kehtivuskinnituse kasutamiseks, kui see on tehtud ja IP aadress avatud siis serveri peal http://localhost:8083/refreshtsl


peab tagastama ok, ehk tehakse TSL(trusted sources list) nimekirja värskendus. Edasi on juba ASP.NET koodi osa, ehk lisad projekti ASMX veebiteenuse, näites on nimi bdoc.asmx

ja tema code-behind koodi päisesse

[System.Web.Script.Services.ScriptService]
public class bdoc : System.Web.Services.WebService

ehk lubad JavaScriptil/jQueryl ASP.NET veebiteenusega suhelda.

ASMX veebiteenuse meetod Port, mis tootab nii, et ASP.NET koodis veebilehel pöördutakse jQuery kaudu ASMX meetodi Port poole, mis teeb päringu Java Spring Boot Service Wrapperisse http://localhost:8083/port, saab sealt vastuse ja tagastab tagasi veebilehele

[WebMethod]
[ScriptMethod(UseHttpGet = true)]
    public void Port()
    {
        string responseFromServer = "";
        string url = "http://localhost:8083/port";     
        try
        {
            WebRequest request = WebRequest.Create(url);
            ((HttpWebRequest)request).UserAgent = "Kampus Web";
            WebResponse response = request.GetResponse();
            Stream dataStream = response.GetResponseStream();
            StreamReader reader = new StreamReader(dataStream);
            responseFromServer = reader.ReadToEnd();

            reader.Close();
            dataStream.Close();
            response.Close();

        }
        catch (WebException ex)
        {
            responseFromServer = ex.Message;
            if (ex.InnerException != null)
            {
                responseFromServer += (" " + ex.InnerException.Message);
            }
        }
        catch (SystemException ex)
        {
            responseFromServer = ex.Message;
        }
        Digest vastus = new Digest();
        vastus.result = responseFromServer;
        vastus.hex = responseFromServer;
        responseFromServer = Newtonsoft.Json.JsonConvert.SerializeObject(vastus);
        Context.Response.Clear();
        Context.Response.ContentType = "application/json;charset=UTF-8";  //see peab olema, muidu ei hakka jquery front-endis tööle, vajab JSON formaati
        Context.Response.AddHeader("content-length", responseFromServer.Length.ToString());
        Context.Response.Flush();
        Context.Response.Output.Write(responseFromServer);
    }

jQuery väljakutse ASPX lehe peal olevast HTML ButtonPort input nupust

input type="button" id="ButtonPort" class="actionButton" value="Kontrolli ASMX BDOC"

Päring töötab nii, ehk

1. Sirvikust jQuery pöördumine ASP.NET /bdoc.asmx/Port meetodisse
2. ASMX meetod Port teeb serveris päringu Java Spring Boot http://localhost:8083/port aadressil
3. Saadud vastuse tagastab ASMX meetod Port sirviku jQueryle


$("#ButtonPort").on("click", function () {
 console.log("Port ");                 
 $.get("/bdoc.asmx/Port", function (data, status) {
 console.log("Port " + data.hex);
 $("#<%=LabelBdoc.ClientID %>").text(status);
 alert("Data: " + data.hex + "\nStatus: " + status);
});
});



Sama Java Spring Boot http://localhost:8083/port väljakutse serveri poolel, ehk ASP.NET code-behind nupu Click meetod kus serveri back-end pöördub otse Java Spring Boot Windows Service wrapperi poole

protected void ButtonBDOC_Click(object sender, EventArgs e)
    {
        string url = "http://localhost:8083/port";
        this.LabelBdoc.Visible = true;
        //https://docs.microsoft.com/en-us/dotnet/framework/network-programming/how-to-request-data-using-the-webrequest-class
        try
        {
            WebRequest request = WebRequest.Create(url);
            ((HttpWebRequest)request).UserAgent = "Kampus WebAdmin ButtonBDOC_Click";
            WebResponse response = request.GetResponse();
            Stream dataStream = response.GetResponseStream();
            StreamReader reader = new StreamReader(dataStream);
            string responseFromServer = reader.ReadToEnd();
            this.LabelBdoc.Text = responseFromServer;
            reader.Close();
            dataStream.Close();
            response.Close();

        }
        catch (WebException ex)
        {
            this.CustomValidator1.ErrorMessage = ex.Message;
            this.CustomValidator1.IsValid = false;
            if (ex.InnerException != null)
            {
                this.LabelBdoc.Text = url + " " + ex.InnerException.Message;
            }
        }
        catch (SystemException ex)
        {
            this.CustomValidator1.ErrorMessage = url + " " + ex.Message;
            this.CustomValidator1.IsValid = false;
        }
    }


Kaks võimalust, kuidas Java Spring Boot Windows Service wrapperi kaudu suhelda, kas front-endis kus pöördutakse läbi ASMX veebimeetodi või server-side kus minnakse otse.

Kui on vaja ASP.NET koodist ASMX veebimeetodile Session -i kaudu väärtust edasi anda
siis ASMX meetodi päisesse lisad [WebMethod(EnableSession = true)]

[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public void generateFileHash(string certInHex)
{
int failiId = Convert.ToInt32(HttpContext.Current.Session["bdocid"].ToString());
}

nii saad ASP.NET code-behind seatud Session muutuja väärtuse kätte ASMX veebimeetodis

Kui näiteks on GridView nimekiri failidest mida vaja digiallkirjastada




asp:Button ID="BtnSigneeri"  Text="Digiallkirjasta leping" CausesValidation="false" CommandName="Signeeri" CommandArgument='<%# Eval("ID") %>' runat="server"


protected void GridViewFailid_RowCommand(object sender, GridViewCommandEventArgs e)
    {
        if (e.CommandName.Equals("Signeeri") )
        {
            this.Session["bdocid"] = e.CommandArgument.ToString();  //faili ID
            Button butt = (Button)e.CommandSource;
            if (!this.Page.ClientScript.IsClientScriptBlockRegistered("signeeriDokument()"))
            {
                //kuna oleme updatepaneli sees, tuleb seda ScriptManager.RegisterStartupScript meetodit kasutada
                //kutsume välja selle nupuga seotud javascripti
                ScriptManager.RegisterStartupScript(butt, typeof(Button), butt.ClientID, "signeeriDokument()", true);         
            }
        }

Ülal olevas koodis on ka näidatud, kuidas saab serveri poolt code-behind välja kutsuda JavaScripti meetodit
ScriptManager.RegisterStartupScript(butt, typeof(Button), butt.ClientID, "signeeriDokument()", true);

javascripti meetod oma korda kutsub välja jQuery funktsioonide promised

function signeeriDokument() {
    console.log("signeeriDokument klikiti");
    signfile();
}

signfile() on jQuery funktsioonide komplekt promiseid, kus post funktsiooni sees url: "/bdoc.asmx/" + url määratakse ära väljakutsutav ASMX veebiteenuse meetod

$(function () {

    post = function (url, data) {
        console.log("post query:" + url);
        return new Promise(function (resolve, reject) {
            $.ajax({
                url: "/bdoc.asmx/" + url,
                type: "POST",
                data: data
            }).done(function (data) {
                console.log("post done data.result " + data.result);
                if (data.result !== "ok") {
                    $("#LabelBdoc").text(data.result);
                    reject(Error(data.result))
                } else {
                    resolve(data);
                }
            }).fail(function () {
                reject(Error("Post operation failed"));
            });
        });
    };


    //olemasolevalt konteinerilt räsi küsimine
    getContainerToSign = function (certInHex) {
        console.log("getContainerToSign " + certInHex);
        return post("getContainerToSign", { certInHex: certInHex })
    };

    fetchFileHash = function (certInHex) {
        console.log("generateFileHash ");
        return post("generateFileHash", { certInHex: certInHex })
    };

    createContainer = function (signatureInHex) {
        console.log("createContainer " + signatureInHex);
        return post("createContainer", { signatureInHex: signatureInHex });
    };

    addSignToContainer = function (signatureInHex) {
        console.log("addSignToContainer " + signatureInHex);
        return post("addSignToContainer", { signatureInHex: signatureInHex });
    };


    signfile = function () {
        var cert;
        naitanupp("LabelBdoc");
        $("#LabelBdoc").text("Loen ID-kaardilt sertifikaati");
        console.log("enne signfile window.hwcrypto.getCertificate");
        window.hwcrypto.getCertificate({ lang: 'en' }).then(function (certificate) {
            cert = certificate;
            $("#LabelBdoc").text("Koostan räsi");
            console.log("getCertificate päring ");
            return fetchFileHash(certificate.hex);
        }).then(function (digest) {              
            console.log("digest " + digest.hex);
            $("#LabelBdoc").text("Signeerin");
            return window.hwcrypto.sign(cert, { type: 'SHA-256', hex: digest.hex }, { lang: 'en' });
        }).then(function (signature) {
            console.log("createcontainer");
            $("#LabelBdoc").text("Loon konteinerit");
            return createContainer(signature.hex);
        }).then(function (result) {
            console.log("container is ready for download " + result.result);                         
            $("#LabelBdoc").text(result.result);              
            window.location = window.location;
        }).catch(err => {
            $("#LabelBdoc").text(err);              
        });
    };
});

ASP.NET Labelil nimega LabelBdoc peab ClientIDMode="Static" olema määratud, et tema ID ei muutuks kompileerimise käigus jQuery kirjutab sinna sisse infot protsessi edenemise kohta $("#LabelBdoc").text("Signeerin");

asp:Label ID="LabelBdoc" CssClass="globalNote" ClientIDMode="Static" runat="server"

Kogu protsessi juhib jQuery signfile funktsioon, küsib ID kaardilt sertifikaadi, käib ASMX veebimeetoditelt küsimas faili räsi, signeerib selle ja lõpuks saadab päringuga andmed konteineri tegemiseks.

ASMX meetodid mis käivad JavaSpring Boot Windows Service wrapperisse andmeid saatmas ja salvestavad vastuvõetu SQL SERVER-i tabelitesse


[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
    public void generateFileHash(string certInHex)
    {
        Digest vastus = new Digest();
        byte[] byteArray = null;
        string fileName = "";
        int failiId =  Convert.ToInt32(HttpContext.Current.Session["bdocid"].ToString());     
        string contype = "";
        try
        {
            String connection = Configuration.ConnectionString;
            using (SqlConnection konn = new SqlConnection(connection))
            {
                SqlCommand komm = new SqlCommand("[dbo].[CONTRACT_FILE_KUIDO_S]", konn);
                komm.CommandType = CommandType.StoredProcedure;
                komm.Parameters.AddWithValue("@fileid", failiId);
                konn.Open();
                SqlDataReader red = komm.ExecuteReader();
                while (red.Read())
                {
                    fileName = red["FILE_NAME"].ToString();
                    contype = red["ADVERTISING_FILE_CONTENT_TYPE"].ToString();
                    byteArray = (byte[])red["FILE_CONTENT"];
                    break;
                }
                red.Close();
                konn.Close();
            }
            string requestURL = "http://localhost:8083/uploadforhash";
            WebClient wc = new WebClient();
            Dictionary<string, object> postParameters = new Dictionary<string, object>();
            // Add your parameters here
            postParameters.Add("file", new BdocUpload.FileParameter(byteArray, Path.GetFileName(fileName), contype));
            postParameters.Add("certInHex", certInHex);
            string userAgent = "KAMPUS generateFileHash";
            HttpWebResponse webResponse = BdocUpload.MultipartFormPost(requestURL, userAgent, postParameters, null, null);
            // Process response
            StreamReader responseReader = new StreamReader(webResponse.GetResponseStream());
            string responseFromServer = responseReader.ReadToEnd();
            webResponse.Close();
            DigestObject djson = JsonConvert.DeserializeObject<DigestObject>(responseFromServer);
            vastus.hex = djson.hex;
            vastus.result = djson.result;
            using (SqlConnection konn = new SqlConnection(connection)) //salvestame Conteineri sisu ajutiselt ära
            {
                SqlCommand komm = new SqlCommand("DBO.CONTRACT_FILE_BDOC_TEMP_U", konn);
                komm.CommandType = CommandType.StoredProcedure;
                komm.Parameters.AddWithValue("@fileid", Convert.ToInt32(this.Session["bdocid"].ToString()));
                komm.Parameters.AddWithValue("@tempdatatosign", djson.datatosign);
                komm.Parameters.AddWithValue("@tempcontainersisu", djson.container);
                konn.Open();
                komm.ExecuteNonQuery();
                konn.Close();
            }
        }
        catch (System.Web.HttpException ex)
        {
            vastus.result = ex.Message;
        }
        catch (SystemException ex)
        {
            vastus.result = ex.Message;
        }
        string jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(vastus);  //teeme vastuse json stringiks

        Context.Response.Clear();
        Context.Response.ContentType = "application/json;charset=UTF-8";  //see peab olema, muidu ei hakka jquery front-endis tööle, vajab JSON formaati
        Context.Response.AddHeader("content-length", jsonString.Length.ToString());
        Context.Response.Flush();
        Context.Response.Output.Write(jsonString);
    }

    [WebMethod(EnableSession = true)]
    [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
    public void createContainer(string signatureInHex)
    {
        int failiId = Convert.ToInt32(HttpContext.Current.Session["bdocid"].ToString());
     
        byte[] datatosign = null;
        byte[] container = null;
        String connection = Configuration.ConnectionString;
        using (SqlConnection konn = new SqlConnection(connection))
        {
            SqlCommand komm = new SqlCommand("DBO.CONTRACT_FILE_KUIDO_S", konn);
            komm.CommandType = CommandType.StoredProcedure;
            komm.Parameters.AddWithValue("@fileid", failiId);
            konn.Open();
            SqlDataReader red = komm.ExecuteReader();
            while (red.Read())
            {
                container = (byte[])red["TEMPCONTAINERSISU"];
                datatosign = (byte[])red["TEMPDATATOSIGN"];
                break;
            }
            red.Close();
            konn.Close();
        }
        Digest vastus = new Digest();
        string requestURL = "http://localhost:8083/createContainer";
        WebClient wc = new WebClient();
        Dictionary<string, object> postParameters = new Dictionary<string, object>();
        // Add your parameters here  "tempcontainer", "bytearray" on koha täiteks
        postParameters.Add("file", new BdocUpload.FileParameter(container, "tempcontainer", "bytearray"));
        postParameters.Add("dfile", new BdocUpload.FileParameter(datatosign, "tempdatatosign", "bytearray"));
        postParameters.Add("signatureInHex", signatureInHex);
        string userAgent = "KAMPUS createContainer";
        HttpWebResponse webResponse = BdocUpload.MultipartFormPost(requestURL, userAgent, postParameters, null, null);
        // Process response
        StreamReader responseReader = new StreamReader(webResponse.GetResponseStream());
        string responseFromServer = responseReader.ReadToEnd();
        webResponse.Close();
        DigestObject djson = JsonConvert.DeserializeObject<DigestObject>(responseFromServer);
        vastus.result = djson.result;
        try
        {
            using (SqlConnection konn = new SqlConnection(connection)) //salvestame BDOC Conteineri sisu
            {
                SqlCommand komm = new SqlCommand("DBO.CONTRACT_FILE_BDOC_U", konn);
                komm.CommandType = CommandType.StoredProcedure;
                komm.Parameters.AddWithValue("@fileid", Convert.ToInt32(failiId));
                komm.Parameters.AddWithValue("@bdocfailisisutyyp", djson.hex);
                komm.Parameters.AddWithValue("@bdocfailisisu", djson.container);
                //komm.Parameters.AddWithValue("@tempcontainersisu", djson.datatosign);
                konn.Open();
                komm.ExecuteNonQuery();
                konn.Close();
            }
        }
        catch (SystemException ex)
        {
            vastus.result = ex.Message;
        }
        string jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(vastus);  //teeme vastuse json stringiks
        Context.Response.Clear();
        Context.Response.ContentType = "application/json;charset=UTF-8";  //see peab olema, muidu ei hakka jquery front-endis tööle, vajab JSON formaati
        Context.Response.AddHeader("content-length", jsonString.Length.ToString());
        Context.Response.Flush();
        Context.Response.Output.Write(jsonString);
    }

Java Spring Boot @RestController public class SigningController teeb ära digiallkirjastamise osad.


ASMX saadab faile Java Spring Boot Service Wrapperile multipart form data-na
https://www.c-sharpcorner.com/article/upload-any-file-using-http-post-multipart-form-data/

Selleks, et sirvikus jQuery saaks üldse teha päringuid ASMX veebimeetodite vastu tuleb web.config failis lubada vastavad veebiteenuste protokollid.



JSON andmevahtuseks ASMX ja Java Spring Booti vahel tuleb Java Spring Boot klassid kloonida ASP.NET rakendusse, Newtonsoft.Json package kasutamiseks

public class Signatuur
{
    public Signatuur()
    {
    }
    public string SubjectName { get; set; }
    public DateTime ClaimedSigningTime { get; set; }
    public String issuerName { get; set; }

    public String errors { get; set; }
}

public class Signatuurid
{
    public Signatuurid()
    {
    }
    public string result { get; set; }
    public List<Signatuur> signatuurid { get; set; }
}


public class DigestObject
{
    public DigestObject()
    {
    }

    public string result { get; set; }
    public string hex { get; set; }
    public byte[] datatosign { get; set; }
    public byte[] container { get; set; }
}