Avatar billede rasmuslh Nybegynder
23. februar 2010 - 10:40 Der er 19 kommentarer og
1 løsning

Skrive SOAP reply fra webservice til XML-fil

Hej
Jeg er data warehouse udvikler og har fået til opgaven at udtrække data fra en webservice. Den eneste måde jeg kan tilgå denne webservice er ved at kode det og det er absolut ikke min stærke side. Jeg har fået hul igennem til webservicen i en Cookie-container da webservicen er session/cookiebaseret.

Mit problem er at ikke rigtig ved hvordan jeg skal trække soap-repliet ud. Jeg har både prøvet at smide det ud i en fil og smide det ud i en consol, men jeg kan ikke finde ud af få det smidt ud på en ordentligt måde.

Følgende fungerer:

public void Main()
        {
dk.bilstatistik.regdata.RegDataService svc = new    dk.bilstatistik.regdata.RegDataService();
svc.CookieContainer = new System.Net.CookieContainer();
svc.Init("...", "...");

Object test = svc.HentNyesteBestand()

.... her skal repliet skrives til en XML fil

}                 

De metoder jeg har til rådighed er beskrevet her: http://regdata.bilstatistik.dk/RegDataService.asmx

HentNyesteBestand skulle gerne give mig en masse stamdata på biler, men som sagt ved jeg ikke hvordan man får skrevet det til et XML-document.

jeg vil helst have det i et XML-dokument da jeg så kan arbejde videre med det som enhver anden kilde i mit ETL-miljø.

På forhånd tak.
Rasmus
Avatar billede janus_007 Nybegynder
23. februar 2010 - 21:16 #1
Det er uhyre simpelt:


public void Main()
        {
dk.bilstatistik.regdata.RegDataService svc = new    dk.bilstatistik.regdata.RegDataService();
svc.CookieContainer = new System.Net.CookieContainer();
svc.Init("...", "...");

//her kan vi ligeså godt parse med det samme, istedet for at smide xml'en ind i et object.

var test = XDocument.Parse( svc.HentNyesteBestand() );
test.Save(@"C:\Temp\test.xml);


}   

XDocument ligger i System.Linq.Xml : http://msdn.microsoft.com/en-us/library/bb551426.aspx

Og XDocument tillader dig at manipulere og læse Xml som du lyster :)
Avatar billede arne_v Ekspert
24. februar 2010 - 03:34 #2
Returnerer svc.HentNyesteBestand() en string med XML eller returnerer den en instans af en custom klasse eller en collection af en custom klasse ?

Hvis det er en string med XML, så er det bare at gemme den til en fil. En StreamWriter er formentligt det mest oplagte.

Hvis det er en instans af en custom klasse eller en collection af en custom klasse, så skal du have konverteret dette til XML inden du udskriver. En mulighed for dette er XmlSerializer klassen.

Jeg vil fraråde at hapse den rå SOAP XML ved at udskifte WS stub med WebClient/(Http)WebRequest. Der vil være alt for meget junk i det XML.
Avatar billede rasmuslh Nybegynder
24. februar 2010 - 08:42 #3
Hej arne

Tak for svaret. Jeg er ret sikker på at det er en collection den returnerer for når jeg forsøger at smide det ud i en streng får jeg kun object-referencen, men igen jeg er ved ikke så meget om programmering. 

Når jeg "hover" over metode-kaldet i Visual Studio står der

dk.bilstatistik.regdata.RegDataService.RegDataPost[] RegDataService.HentNyesteBestand()

Det må vel betyde at det er en collection af custom klassen RegDataPost[] der returneres ikke?
Avatar billede arne_v Ekspert
24. februar 2010 - 15:16 #4
Det er et array af RegDataPost[] !

Hvis RegDataPost er serializable, saa burde den kunne XML serializes.
Avatar billede rasmuslh Nybegynder
24. februar 2010 - 15:37 #5
Hej arne

har du et link til eksempel på hvordan man bruger XMLserialixer på den måde du tænker så jeg tager "udgangspunkt i den rigtige type eksempel".

På forhånd tak.
Rasmus
Avatar billede arne_v Ekspert
24. februar 2010 - 16:02 #6
Hurtig demo:

using System;
using System.Xml.Serialization;

namespace E
{
    public class Data
    {
        public int Iv { get; set; }
        public string Sv { get; set; }
    }
    public class Program
    {
        public static void Main(string[] args)
        {
            Data[] d = new Data[3];
            d[0] = new Data { Iv=123, Sv="ABC" };
            d[1] = new Data { Iv=456, Sv="DEF" };
            d[2] = new Data { Iv=789, Sv="GHI" };
            XmlSerializer ser = new XmlSerializer(typeof(Data[]));
            ser.Serialize(Console.Out, d);
            Console.ReadKey();
        }
    }
}

udskriver:

<?xml version="1.0" encoding="IBM437"?>
<ArrayOfData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Data>
    <Iv>123</Iv>
    <Sv>ABC</Sv>
  </Data>
  <Data>
    <Iv>456</Iv>
    <Sv>DEF</Sv>
  </Data>
  <Data>
    <Iv>789</Iv>
    <Sv>GHI</Sv>
  </Data>
</ArrayOfData>
Avatar billede rasmuslh Nybegynder
24. februar 2010 - 16:42 #7
Hej arne

Tak for eksemplet. Nu har jeg forsøgt at lave noget tilsvarende, men er dog lidt i tvivl om hvordan jeg skal erklære objeket ser.

Jeg forsøgte noget ala det her, men der får jeg en typecast error:


        public class IDBetegnelse {}

        public void Main()
        {

            //Webservice DBI
            dk.bilstatistik.regdata.RegDataService svc = new dk.bilstatistik.regdata.RegDataService();
            svc.CookieContainer = new System.Net.CookieContainer();
            svc.Init("...", "...");

            IDBetegnelse test = new IDBetegnelse();
               
            test = svc.HentBiltyper();
           
            XmlSerializer ser = new XmlSerializer(typeof(IDBetegnelse[]));
            ser.Serialize(Console.Out, test);
            Console.ReadKey(); 



Skal man selv erklære en klasse af den type som metode-kaldet returnerer eller hvordan får man XmlSerializer til at acceptere typeof(Returnværdien).
Avatar billede arne_v Ekspert
24. februar 2010 - 17:18 #8
Den kode ser rigtig ud.

Virker den ikke?
Avatar billede rasmuslh Nybegynder
24. februar 2010 - 18:17 #9
Nej, jeg får følgende fejl:

Cannot implicitly convert type dk.bilstatistik.regdata.IDBetegnelse[]' to csproj.ScriptMain.IDBetegnelse


Skyldes det at der forventes et array eller er det fordi jeg blot har lavet en klasse med samme navn som det returnerede og de som sådan ikke har noget at gøre med hinanden?

Det kan vel ikke være rigtigt at jeg skal erklære en klasse det hedder det samme som den objekttype der forventes returneret?
Avatar billede rasmuslh Nybegynder
24. februar 2010 - 18:38 #10
Hej arne

Nu tænkte jeg mig lidt om og prøvede istedet sådan her:

            //Webservice DBI
            dk.bilstatistik.regdata.RegDataService svc = new dk.bilstatistik.regdata.RegDataService();
            svc.CookieContainer = new System.Net.CookieContainer();
            svc.Init("...", "...");

            dk.bilstatistik.regdata.IDBetegnelse[] test = new dk.bilstatistik.regdata.IDBetegnelse[1000];

            test = svc.HentBiltyper();

            XmlSerializer ser = new XmlSerializer(typeof(dk.bilstatistik.regdata.IDBetegnelse));
            ser.Serialize(Console.Out, test);
            Console.ReadKey();   

Nu kan jeg da builde det, men der er 2 problemer.

For det første vil den kun builde hvis jeg skriver en størrelse på arrayet - 1000 lige nu? Hvordna kan jeg gøre det dynamisk. jeg har jo ingen chance for at vide hvor mange objekter der kommer tilbage?

Derudover fejler koden stadigvæk når den køres:

SSIS package "Package.dtsx" starting.
Error: 0x1 at Script Task: System.Reflection.TargetInvocationException: Destinationen for en aktivering udløste en undtagelse. ---> System.InvalidOperationException: Der opstod en fejl under oprettelse af XML-dokumentet. ---> System.InvalidOperationException: Typen ST_0308cbac94774343ab1e8449501ed7d9.csproj.dk.bilstatistik.regdata.IDBetegnelse[] kan ikke bruges i denne kontekst.
  ved Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterIDBetegnelse.Write2_IDBetegnelse(String n, String ns, Object o, Boolean isNullable, Boolean needType)
  ved Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterIDBetegnelse.Write3_IDBetegnelse(Object o)
  --- Slut på staksporing af indre undtagelser ---
  ved System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
  ved System.Xml.Serialization.XmlSerializer.Serialize(TextWriter textWriter, Object o, XmlSerializerNamespaces namespaces)
  ved System.Xml.Serialization.XmlSerializer.Serialize(TextWriter textWriter, Object o)
  ved ST_0308cbac94774343ab1e8449501ed7d9.csproj.ScriptMain.Main()
  --- Slut på staksporing af indre undtagelser ---
  ved System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
  ved System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
  ved System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
  ved System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
  ved System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams)
  ved System.Type.InvokeMember(String name, BindingFlags invokeAttr, Binder binder, Object target, Object[] args, CultureInfo culture)
  ved Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTATaskScriptingEngine.ExecuteScript()
Task failed: Script Task
SSIS package "Package.dtsx" finished: Success.
Avatar billede arne_v Ekspert
24. februar 2010 - 18:40 #11
dk.bilstatistik.regdata.IDBetegnelse[] test = new dk.bilstatistik.regdata.IDBetegnelse[1000];

test = svc.HentBiltyper();

->

dk.bilstatistik.regdata.IDBetegnelse[] test = svc.HentBiltyper();
Avatar billede arne_v Ekspert
24. februar 2010 - 18:41 #12
og

XmlSerializer ser = new XmlSerializer(typeof(dk.bilstatistik.regdata.IDBetegnelse));

->

XmlSerializer ser = new XmlSerializer(typeof(dk.bilstatistik.regdata.IDBetegnelse[]));
Avatar billede rasmuslh Nybegynder
24. februar 2010 - 18:59 #13
Hmmmh, det virkede som om der skete noget. umiddelbart kom der dog først en fejl med udskriften:


**********

SSIS package "Package.dtsx" starting.
Error: 0x1 at Script Task: System.Reflection.TargetInvocationException: Destinationen for en aktivering udløste en undtagelse. ---> System.InvalidOperationException: Det er ikke muligt at læse nøgler, når ingen af programmerne har en konsol, eller når konsolinput er blevet omdirigeret fra en fil. Prøv Console.Read.
  ved System.Console.ReadKey(Boolean intercept)
  ved ST_0308cbac94774343ab1e8449501ed7d9.csproj.ScriptMain.Main()
  --- Slut på staksporing af indre undtagelser ---
  ved System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
  ved System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
  ved System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
  ved System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
  ved System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams)
  ved System.Type.InvokeMember(String name, BindingFlags invokeAttr, Binder binder, Object target, Object[] args, CultureInfo culture)
  ved Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTATaskScriptingEngine.ExecuteScript()
Task failed: Script Task
SSIS package "Package.dtsx" finished: Success.


**********


Jeg rettede derefter:

Console.ReadKey();

-->

Console.Read();   

Så fejlede den ikke, men der sker ikke noget.
 
Kan man i stedet skrive direkte til en fil i stedet så man kan se om der "sker" noget?
Avatar billede arne_v Ekspert
24. februar 2010 - 19:22 #14
ser.Serialize(Console.Out, test);
Console.ReadKey();

->

Stream stm = new FileStream(@"C:\foobar.xml", FileMode.Create, FileAccess.Write);
ser.Serialize(stm, test);
stm.Close();
Avatar billede rasmuslh Nybegynder
24. februar 2010 - 19:44 #15
Fantastisk. Nu er der hul igennem. Så er det bare at gemme det et sted og hive dem ind i mit ETL-værktøj.

Det eneste lille mén er at når jeg kalder nogle af webservices får jeg et timeout. Jeg har fået af vide at serveren først timer ud efter 20 minutter så det må næsten være noget hos mig.

Har du noget bud på om det kan være koden der timer ud eller man kan læse asynkront?


Såfremt det ikke siger dig noget er jeg rigelig taknemmelig for din hjælp og vil meget gerne give dig point.

Endnu engang tak for den store hjælp.

Rasmus
Avatar billede arne_v Ekspert
24. februar 2010 - 19:51 #16
Lidt googling antyder at du kan:

svc.Endpoint.Binding.OpenTimeout = TimeSpan.FromSeconds(10);
Avatar billede arne_v Ekspert
24. februar 2010 - 19:51 #17
svar
Avatar billede rasmuslh Nybegynder
24. februar 2010 - 20:05 #18
Tak for den kæmpe hjælp.
Avatar billede janus_007 Nybegynder
25. februar 2010 - 00:25 #19
Rasmus -> Hvilket ETL værktøj bruger du?
Avatar billede rasmuslh Nybegynder
25. februar 2010 - 08:45 #20
Integration Services 2008 i det her tilfælde. Der findes jo en webservice komponent den understøtter bare ikke cookies/sessions.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester