XMLPORT.IMPORT fails while using with webservice

gdkve9gdkve9 Member Posts: 161
edited 2012-03-07 in NAV Three Tier
Hi guys,

I am stuck at one point while using XMLPORTS. I have created an XMLPORT and a Codeunit for importing the data from an xml file. When I run the Codeunit locally, the data gets imported and everything looks fine.

The problem is, when I try to run the same Codeunit using Web Service, the XMLPORT.IMPORT function fails and returns the exception "Import Unsuccessful". Any ideas resolving the same would be highly appretiated.

Awaiting on the responses. Thanks in advance.

Following is the code that I am using for Import.

SendOrderDetails() FileExists : Boolean
IF EXISTS('C:\inetpub\wwwroot\Import Files\OrderDetails.xml') THEN
BEGIN
IF TestFile.OPEN('C:\inetpub\wwwroot\Import Files\OrderDetails.xml') THEN
BEGIN
TestFile.CREATEINSTREAM(VarInStream);
IF XMLPORT.IMPORT(50007,VarInStream) THEN
FileExists := TRUE
ELSE
ERROR('Import Unsuccessful');
END ELSE
ERROR('Error Opening file');
TestFile.CLOSE;
END ELSE
FileExists := FALSE;
Dilip
Falling down is not a defeat..defeat is when you refuse to get up.

Comments

  • PloegPloeg Member Posts: 70
    A XML-Port look for 'C:\inetpub\wwwroot\Import Files\OrderDetails.xml' at the server where the service tier is running. So when you try to run this code it won't find the path because it is not there.

    You can use the UPLOAD function to copy the file to a temp folder on the service tier and try to import it from there (store the path in a variable).
  • carboncarbon Member Posts: 22
    I recommend do not use XML file stored on a disk (if it is possible). Be sure a function in the published codeunit can have parameter - type XMLport. In this case you can use this simple code in codeunit (InsertIncident is name of published method):
    InsertIncident(VAR parXmlPort : XMLport XMLport50015)
    parXmlPort.IMPORT();
  • gdkve9gdkve9 Member Posts: 161
    Hi Ploeg,

    Thanks for the response.

    I guess, that should not be the problem based on below two assumptions.

    1. The TESTFILE.OPEN function returns true in the same code, which means it is able to open the file from the path. It just fails when calling the IMPORT function of the XMLPort after the xml file has been read from the path and hence throws the exception "Import Unsuccess". If there is problem in finding the path, the exception should have been "Error Opening File" which is mentioned as error msg in the sample code.

    2. Secondly, I am using the following code for export which works fine with the webservice call.

    TestFile.CREATE('C:\inetpub\wwwroot\Export Files\LoginDetails.xml');
    TestFile.CREATEOUTSTREAM(TestStream);
    XMLPORT.EXPORT(50004,TestStream);
    TestFile.CLOSE;

    Thanks again.
    Dilip
    Falling down is not a defeat..defeat is when you refuse to get up.
  • PloegPloeg Member Posts: 70
    It is indeed the IMPORT function that is the trouble. IMPORT and EXPORT are two completely different things.
    You could try the following code:

    LOCAL VARS:
    XMLFile -> File		
    XMLStream -> InStream		
    lPath -> Text (500)
    lCduCommonDialogManagement -> Codeunit (Common Dialog Management)	
    ConfPersMgt -> Codeunit (Conf./Personalization Mgt.)	
    TempFile -> File		
    Filename -> File	
    
    TEXT CONSTANT:
    LTXT_Filter -> XML files (*.xml)|*.xml|All files (*.*)|*.*	
    
    IF ISSERVICETIER THEN
    BEGIN
      TempFile.CREATETEMPFILE;
      lPath := TempFile.NAME + '.xml';
      TempFile.CLOSE;
      IF UPLOAD('Import XML', '',LTXT_Filter,'',lPath) THEN BEGIN
        XMLFile.OPEN(lPath);
        XMLFile.CREATEINSTREAM(XMLStream);
        XMLPORT.IMPORT([YOUR IMPORT], XMLStream);
        XMLFile.CLOSE;
      END;
    END ELSE
    BEGIN
      lPath := lCduCommonDialogManagement.OpenFile(
        'Select a Import file', '', 4, LTXT_Filter, 0);
    
      IF lPath <> '' THEN BEGIN
        XMLFile.OPEN(lPath);
        XMLFile.CREATEINSTREAM(XMLStream);
        XMLPORT.IMPORT([YOUR IMPORT], XMLStream);
        XMLFile.CLOSE;
      END;
    END;
    
  • gdkve9gdkve9 Member Posts: 161
    Hi Ploeg,

    Since I am exposing the codeunit as a web service, hope I cannot use UPLOAD function as it promts for a dialog box for selecting the file.

    Instead I have tried using the below code:
    PushOrderDetails(VAR VarBigTxt : BigText) fileImport : Boolean
    lrecTempBlob.Blob.CREATEOUTSTREAM(OutStr);
    VarBigTxt.WRITE(OutStr);
    lrecTempBlob.Blob.CREATEINSTREAM(InStr);
    VarXML.SETSOURCE(InStr);
    IF VarXML.IMPORT THEN
      fileImport := TRUE
    ELSE
      ERROR('Import Unsuccessful');
    

    The above code works fine when run locally but I am really stuck why the web service call cannot run the varxml.import function and it throws the exception "Import Unsuccessful". Really stuck ](*,) ](*,)

    Going mad :x
    Dilip
    Falling down is not a defeat..defeat is when you refuse to get up.
  • kinekine Member Posts: 12,562
    Try to call the import out of IF-Then to let NAV throw the original runtime error.
    Kamil Sacek
    MVP - Dynamics NAV
    My BLOG
    NAVERTICA a.s.
  • gdkve9gdkve9 Member Posts: 161
    Hi Kamil,

    In that case, the web service throws the exception as shown in the attachment. I doesnt have any clue why is this happening when the same is working fine locally.

    :-k :-k :-k :-k :-k
    Dilip
    Falling down is not a defeat..defeat is when you refuse to get up.
  • kinekine Member Posts: 12,562
    THis exception means that you have confirm or dialog used in the code, but it means definitely, that the code is called at all... ;-)
    Kamil Sacek
    MVP - Dynamics NAV
    My BLOG
    NAVERTICA a.s.
  • gdkve9gdkve9 Member Posts: 161
    Thanks Kamil for the reply.

    But the XMLPORT which I am using for IMPORT doesnt have any set of code. Any idea where the confirm or dialog possiblities would come while using IMPORT??
    Dilip
    Falling down is not a defeat..defeat is when you refuse to get up.
  • kinekine Member Posts: 12,562
    May be some OnValdiate or OnInsert is called in some table? How is the XMLPort called? It is as parameter of the function? Or through local variable?
    Kamil Sacek
    MVP - Dynamics NAV
    My BLOG
    NAVERTICA a.s.
  • gdkve9gdkve9 Member Posts: 161
    Is called through local variable.

    Also for testing, I am trying to import only the primary key value of the table. And the table doesnt have any set of code in the OnIsert() and OnValidate() of the field which I am using in the XMLPORT.

    Still the problem is same ](*,)
    Dilip
    Falling down is not a defeat..defeat is when you refuse to get up.
  • deV.chdeV.ch Member Posts: 543
    Run the code from classic client or rtc client and see what the callback is (a confirm, a form/page, etc). then search for that.
  • kinekine Member Posts: 12,562
    May be the XMLPort is asking for the file name? :-)
    Kamil Sacek
    MVP - Dynamics NAV
    My BLOG
    NAVERTICA a.s.
  • carboncarbon Member Posts: 22
    I solved the same error several moths ago. Unfortunately I can't remember what reason was that. I'm not sure but I have feeling that temporary table (Temporary property) and something around this was the cause.
  • gdkve9gdkve9 Member Posts: 161
    I could finally analyse why the problem was.. And it was due to some OCX control function calls of LS Retail. I could able to handle the function calls and now the import function works like a gem through webservice.
    But...
    I have gone into the next problem now with the same web service. The next tast is to print the imported data from a windows printer. For that...

    1. I have created a very simple report with just one data item
    2. one control in the body section of that.
    3. No code on the report.
    4. Layout is created.

    When I try to run the report, the same works fine locally, but again problem is when run using web service.

    The system throws an exception saying "Callback Functions are not allowed"

    Any clue where the user interface is obstructing with the following two line of simple code.
    IF ISSERVICETIER() THEN
      REPORT.RUNMODAL(50201,FALSE,FALSE,Record);
    
    Awaiting on some ideas in breaking the same :-k :-k

    Thanks all in advance.
    Dilip
    Falling down is not a defeat..defeat is when you refuse to get up.
  • kinekine Member Posts: 12,562
    I am not sure now, but I think that the problem is, that webservices cannot print... you can save the output into PDF and somehow send the pdf to the printer...
    Kamil Sacek
    MVP - Dynamics NAV
    My BLOG
    NAVERTICA a.s.
  • deV.chdeV.ch Member Posts: 543
    Yes printing trough webservice is not possible. As Kine sais you need to generate a PDF and then print that. I discribed that in this topic:
    http://www.mibuso.com/forum/viewtopic.php?f=32&t=46507&hilit=print+pdf

    Please read last page carefully. I ended up writing a .net service that uses a FileSystemWatcher Class to watch a folder for incoming pdfs which had the printer name encoded in their filename to print the pdfs trough foxxit pdf reader (the external service is needed so you can run it under a domain user which you can assign printers to). I guess that's the best solution to do this!

    Note: If you set up your NST to run under a domain account then you probably don't need the external service, you can do it with .net interop so foxxit reader would run under the context of a user that has printers assigned.
  • gdkve9gdkve9 Member Posts: 161
    deV.ch wrote:
    Ok i found a solution that prints quick enough for my requirements:

    -I generate the PDF with SAVEASPDF
    -I use R2's DotNet Interop to use a DLL from Forensictools.net that can print PDF without the need of Acrobat Reader (But Printer must support PostScript)
    The DLL is free! http://forensictools.net/
    I tried for the dll, but the website says the download doesnt exist. Pls. suggest where can I get the same.

    Also, as we are working on NAV 2009 SP1, kindly mention how the below function of your's should be changed as we dont have the dotnet datatype.
    StartProcess(_Filename : Text[250];_Arguments : Text[250])
    Process := Process.Process();
    ProcessInfo := ProcessInfo.ProcessStartInfo(_Filename,_Arguments);
    Process.StartInfo := ProcessInfo;
    Process.Start();
    Process.WaitForExit(10000); // Wait max. 10 sec
    
    Awaiting on your response deV.ch, Thank you in advance.
    Dilip
    Falling down is not a defeat..defeat is when you refuse to get up.
  • deV.chdeV.ch Member Posts: 543
    As i said i suggest to create a .net service that can watch a folder for incoming pdf files and prints these. This way you don't need .net interop (Nav 2009 R2) you simply save your report as pdf (SAVEASPDF) in the folder.

    To save the file you can use this code:
    Printer := GetPrinterSelection(GetIDFromObjectID(ReportShipmentAvis.OBJECTID(FALSE)));
        FileName := GetFileName(Printer);
        SalesHead := _Record;
        SalesHead.SETVIEW(_RecView);
        ReportShipmentAvis.USEREQUESTFORM := FALSE;
        ReportShipmentAvis.SETTABLEVIEW(SalesHead);
        ReportShipmentAvis.SAVEASPDF(FileName);
    

    GetPrinterSelection():
    UserSetup.GET(USERID);
    PrinterSelection.SETRANGE("Report ID", _ReportID);
    PrinterSelection.SETRANGE("User ID", USERID);
    IF PrinterSelection.FINDFIRST THEN
      EXIT(PrinterSelection."Printer Name");
    

    GetFileName():
    Setup.GET;
    
    ServerUtil := ServerUtil.HttpUtility;
    _Printer := ServerUtil.UrlEncodeUnicode(_Printer);
    
    DateAndTime := FORMAT(TODAY,0,'<Month,2><Day,2><Year>') + '_' + FORMAT(TIME,0,'<Hours24>-<Minutes,2>-<Seconds,2>');
    RandomPart := Path.GetRandomFileName();
    FileString := '_%1_%2_Printer[%3].tmp';
    
    FileName := Path.Combine(Setup."PDF File Path", STRSUBSTNO(FileString, COPYSTR(Path.GetFileNameWithoutExtension(RandomPart),1,50),
                             DateAndTime, _Printer));
    
    EXIT(FileName);
    

    The GetFileName Function uses .net interop again, so you will need to rewrite it to get the same result. maybe File.CREATETEMPFILE or something like that to create a unique file name. The Printer Name is encoded since you can't use backslashes etc, in file names. I used .net interop here as well, but there is a Function UrlEncode in NAV Codeunit 801.

    Thats all for the NAV Part.

    Here is the a simplified version of my code in the service that prints the pdf files:
    public partial class Service1 : ServiceBase
        {
            [Conditional("DEBUG_SERVICE")]
            private static void DebugMode()
            {
                Debugger.Break();
            }
    
            public Service1()
            {
                InitializeComponent();
                this.ServiceName = "PDFPrintService";
            }
    
            FileSystemWatcher watcher;
    
            protected override void OnStart(string[] args)
            {
                DebugMode();
                watcher = new FileSystemWatcher();            
                watcher.Path = ConfigurationManager.AppSettings["PDF File Folder"];                
                watcher.Created += new FileSystemEventHandler(watcher_Event);
                watcher.Changed += new FileSystemEventHandler(watcher_Event);
                watcher.Renamed +=new RenamedEventHandler(watcher_Event);
                watcher.EnableRaisingEvents = true;
    
                EventLogHelper.WriteEventLog(String.Format("{0} started", Assembly.GetExecutingAssembly().FullName), EventLogEntryType.Information);
            }        
    
            protected override void OnStop()
            {
                watcher.Dispose();
                EventLogHelper.WriteEventLog(String.Format("{0} stoped", Assembly.GetExecutingAssembly().FullName), EventLogEntryType.Information);
            }
    
    
            void watcher_Event(object sender, FileSystemEventArgs e)
            {            
                try
                {
                    if (Path.GetExtension(e.FullPath).ToLower() == ".pdf")
                    {
                        if (ConfigurationManager.AppSettings["Debug"] == "true")
                            EventLogHelper.WriteEventLog(string.Format("File Found \r\n\r\nFile: {0} ", e.Name), EventLogEntryType.Information);
    
                        string Printer = "";
                        if (e.FullPath.Contains("Printer["))
                        {
                            int start = e.FullPath.IndexOf("[") + 1;
                            int end = e.FullPath.IndexOf("]");
                            Printer = e.FullPath.Substring(start, end - start);
                            Printer = HttpUtility.UrlDecode(Printer).Trim();                    
                        }
    
                        // Get Default Printer if Pritner String Emtpy
                        if (Printer == String.Empty)
                        {
                            PrinterSettings settings = new PrinterSettings();
                            Printer = settings.PrinterName;
                        }            
    
                        PrintPDFHelper.PrintPDF(ConfigurationManager.AppSettings["Foxit Path"], e.FullPath, Printer);
                    }
                }
                catch (Exception ex)
                {
                    EventLogHelper.WriteEventLog("Watcher Event Error ("+e.ChangeType.ToString()+ ") :" + ex.Message, EventLogEntryType.Error);
                }
            }
            
    
        }
    

    And The Code for the PrintPDFHelper.PrintPDF Method
    public static void PrintPDF(string PathPDFReader, string Filename, string Printer)
            {
                
                if(ConfigurationManager.AppSettings["Debug"] == "true")
                    EventLogHelper.WriteEventLog(string.Format("Start Print \r\n\r\nReader:{0} \r\nFile: {1} \r\nPrinter {2}", PathPDFReader, Filename, Printer),EventLogEntryType.Information);
    
                string arguments = "";
                if (Printer == "")
                    arguments = string.Format("-p \"{0}\"", Filename);
                else
                    arguments = string.Format("-t \"{0}\" \"{1}\"", Filename, Printer);
    
                ProcessStartInfo starter = new ProcessStartInfo(PathPDFReader, arguments);
    
                starter.UseShellExecute = false;
                
                Process process = new Process();
                process.StartInfo = starter;
                try
                {
                    int Timeout;
                    if (!int.TryParse(ConfigurationManager.AppSettings["FoxitTimeout"], out Timeout))
                        Timeout = 10000;
    
                    process.Start();                
                    process.WaitForExit(Timeout);
                    if (!process.HasExited)
                    {
                        process.Kill();
                        EventLogHelper.WriteEventLog(String.Format("Document '{0}' can't be printed: \r\nProbably Printer '{1}' not ready", Filename, Printer), EventLogEntryType.Warning);
                    }
                }
                catch (Exception ex)
                {
                    EventLogHelper.WriteEventLog("Foxxit Start Error: " + ex.Message, EventLogEntryType.Error);
                }
                finally
                {
                    try
                    {                    
                        if (ConfigurationManager.AppSettings["DeleteFilesAfterPrint"] == "true")
                            File.Delete(Filename);
                    }
                    catch (Exception ex)
                    {
                        EventLogHelper.WriteEventLog("File Delete Error: " + ex.Message, EventLogEntryType.Error);
                    }
                }
            }
    
  • gdkve9gdkve9 Member Posts: 161
    Hi deV.ch,

    Regrets if I am troubling you, I tried searching for creating a dotnet service but with no success. I have no knowledge on dotnet. Could you pls. mention the steps for the creating the dotnet service with the code u have mentioned as is below and how to use the same for NAV. I would be grateful to u..
    deV.ch wrote:
    Here is the a simplified version of my code in the service that prints the pdf files:
    public partial class Service1 : ServiceBase
        {
            [Conditional("DEBUG_SERVICE")]
            private static void DebugMode()
            {
                Debugger.Break();
            }
    
            public Service1()
            {
                InitializeComponent();
                this.ServiceName = "PDFPrintService";
            }
    
            FileSystemWatcher watcher;
    
            protected override void OnStart(string[] args)
            {
                DebugMode();
                watcher = new FileSystemWatcher();            
                watcher.Path = ConfigurationManager.AppSettings["PDF File Folder"];                
                watcher.Created += new FileSystemEventHandler(watcher_Event);
                watcher.Changed += new FileSystemEventHandler(watcher_Event);
                watcher.Renamed +=new RenamedEventHandler(watcher_Event);
                watcher.EnableRaisingEvents = true;
    
                EventLogHelper.WriteEventLog(String.Format("{0} started", Assembly.GetExecutingAssembly().FullName), EventLogEntryType.Information);
            }        
    
            protected override void OnStop()
            {
                watcher.Dispose();
                EventLogHelper.WriteEventLog(String.Format("{0} stoped", Assembly.GetExecutingAssembly().FullName), EventLogEntryType.Information);
            }
    
    
            void watcher_Event(object sender, FileSystemEventArgs e)
            {            
                try
                {
                    if (Path.GetExtension(e.FullPath).ToLower() == ".pdf")
                    {
                        if (ConfigurationManager.AppSettings["Debug"] == "true")
                            EventLogHelper.WriteEventLog(string.Format("File Found \r\n\r\nFile: {0} ", e.Name), EventLogEntryType.Information);
    
                        string Printer = "";
                        if (e.FullPath.Contains("Printer["))
                        {
                            int start = e.FullPath.IndexOf("[") + 1;
                            int end = e.FullPath.IndexOf("]");
                            Printer = e.FullPath.Substring(start, end - start);
                            Printer = HttpUtility.UrlDecode(Printer).Trim();                    
                        }
    
                        // Get Default Printer if Pritner String Emtpy
                        if (Printer == String.Empty)
                        {
                            PrinterSettings settings = new PrinterSettings();
                            Printer = settings.PrinterName;
                        }            
    
                        PrintPDFHelper.PrintPDF(ConfigurationManager.AppSettings["Foxit Path"], e.FullPath, Printer);
                    }
                }
                catch (Exception ex)
                {
                    EventLogHelper.WriteEventLog("Watcher Event Error ("+e.ChangeType.ToString()+ ") :" + ex.Message, EventLogEntryType.Error);
                }
            }
            
    
        }
    
    And The Code for the PrintPDFHelper.PrintPDF Method
    public static void PrintPDF(string PathPDFReader, string Filename, string Printer)
            {
                
                if(ConfigurationManager.AppSettings["Debug"] == "true")
                    EventLogHelper.WriteEventLog(string.Format("Start Print \r\n\r\nReader:{0} \r\nFile: {1} \r\nPrinter {2}", PathPDFReader, Filename, Printer),EventLogEntryType.Information);
    
                string arguments = "";
                if (Printer == "")
                    arguments = string.Format("-p \"{0}\"", Filename);
                else
                    arguments = string.Format("-t \"{0}\" \"{1}\"", Filename, Printer);
    
                ProcessStartInfo starter = new ProcessStartInfo(PathPDFReader, arguments);
    
                starter.UseShellExecute = false;
                
                Process process = new Process();
                process.StartInfo = starter;
                try
                {
                    int Timeout;
                    if (!int.TryParse(ConfigurationManager.AppSettings["FoxitTimeout"], out Timeout))
                        Timeout = 10000;
    
                    process.Start();                
                    process.WaitForExit(Timeout);
                    if (!process.HasExited)
                    {
                        process.Kill();
                        EventLogHelper.WriteEventLog(String.Format("Document '{0}' can't be printed: \r\nProbably Printer '{1}' not ready", Filename, Printer), EventLogEntryType.Warning);
                    }
                }
                catch (Exception ex)
                {
                    EventLogHelper.WriteEventLog("Foxxit Start Error: " + ex.Message, EventLogEntryType.Error);
                }
                finally
                {
                    try
                    {                    
                        if (ConfigurationManager.AppSettings["DeleteFilesAfterPrint"] == "true")
                            File.Delete(Filename);
                    }
                    catch (Exception ex)
                    {
                        EventLogHelper.WriteEventLog("File Delete Error: " + ex.Message, EventLogEntryType.Error);
                    }
                }
            }
    
    Thanks in advance.
    Dilip
    Falling down is not a defeat..defeat is when you refuse to get up.
  • deV.chdeV.ch Member Posts: 543
    Here is a introduction to windows services: http://www.codeproject.com/Articles/14353/Creating-a-Basic-Windows-Service-in-C

    I provided you my class Service1 which is equal to the class "WindowsService" in this tutorial. You can copy the code in the project you will create.
    Since NAV is pushing in that direction i recommend you getting in touch with the whole .net world. but if you can't get it to work, i recommend you to conntact a .net developer to create this for you.

    Unfortunatly right now i have no time to create a public version of my solution. Maybe i will do this in the near future. I see this could probably help some people, also i see that i should sum the whole topic up in a proper blog post. Since it involves lots of different parts, like permissions, domain users, windows services, pdf readers, etc...

    Let me know if you managed to create the service, once you have this, its almost done.
Sign In or Register to comment.