Question

Question:

The below program should read all XML report files (*.rdl files) in the folder specified in strPat, modify them according to my code, and save the modified XML file in folder <User>/Desktop/AutoModifiedReports/filename.rdl, and then copy the modified XML file back to the folder in strPat.

My problem is that I get an unauthorized access Exception in the CopyBack procedure. The program can write and overwrite a file in the target directory. Just when it first reads, modifies and then copies back, it gets an unauthorized access exception.

This happens in

 public static void CopyBack(string strFileName)
        {
            string strSavePath = GetSavePath();
            strSavePath = System.IO.Path.Combine(strSavePath, System.IO.Path.GetFileName(strFileName));

            if (System.IO.File.Exists(strSavePath))
            {
                System.IO.File.Copy(strSavePath, strFileName, true); // Exception - Unauthorized access
            }

        } // End Sub CopyBack

I don't see any place where I leave a stream open or the file locked.
Can anybody tell me what it is exactly that I am doing wrong, and how I can correct it ?

using System;
using System.Collections.Generic;
using System.Windows.Forms;


namespace ReportModifier
{


    static class MalfunctioningProgram
    {

        public static string strLogPath = GetLogFilePath();


        public static string GetSavePath()
        {
            string strSavePath = System.Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
            strSavePath = System.IO.Path.Combine(strSavePath, "AutoModifiedReports");


            if (!System.IO.Directory.Exists(strSavePath))
                System.IO.Directory.CreateDirectory(strSavePath);

            return strSavePath;
        } // End Function GetSavePath


        public static string GetLogFilePath()
        { 
            string strLogfileLocation = System.IO.Path.Combine(GetSavePath(), "log.txt");

            if (System.IO.File.Exists(strLogfileLocation))
                System.IO.File.Delete(strLogfileLocation);

            return strLogfileLocation;
        } // End Function GetLogFilePath


        public static void LogMessage(string strMessage)
        {
            // Console.WriteLine(strMessage);
            System.IO.File.AppendAllText(strLogPath, strMessage + Environment.NewLine, System.Text.Encoding.UTF8);
        } // End Sub LogMessage


        public static void LogMessage(string str, params object[] args)
        {
            LogMessage(string.Format(str, args));
        } // End Sub LogMessage



        public static System.Xml.XmlDocument File2XmlDocument(string strFileName)
        {
            // http://blogs.msdn.com/b/tolong/archive/2007/11/15/read-write-xml-in-memory-stream.aspx
            System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
            // doc.Load(memorystream);
            // doc.Load(FILE_NAME);

            using (System.Xml.XmlTextReader xtrReader = new System.Xml.XmlTextReader(strFileName))
            {
                doc.Load(xtrReader);
                xtrReader.Close();
            } // End Using xtrReader

            return doc;
        } // End Function File2XmlDocument


        public static System.Xml.XmlNamespaceManager GetReportNamespaceManager(System.Xml.XmlDocument doc)
        {
            System.Xml.XmlNamespaceManager nsmgr = new System.Xml.XmlNamespaceManager(doc.NameTable);
            nsmgr.AddNamespace("dft", "http://schemas.microsoft.com/sqlserver/reporting/2005/01/reportdefinition");

            return nsmgr;
        } // End Function GetReportNamespaceManager


        public static void SaveDocument(System.Xml.XmlDocument doc, string strFilename)
        {
            SaveDocument(doc, strFilename, false);
        } // End Sub SaveDocument


        public static void SaveDocument(System.Xml.XmlDocument doc, string strFilename, bool bDoReplace)
        {
            string strSavePath = GetSavePath();
            strSavePath = System.IO.Path.Combine(strSavePath, System.IO.Path.GetFileName(strFilename));

            if (bDoReplace)
            {
                doc.LoadXml(doc.OuterXml.Replace("xmlns=\"\"", ""));
            }

            using (System.Xml.XmlTextWriter xtw = new System.Xml.XmlTextWriter(strSavePath, System.Text.Encoding.UTF8))
            {
                xtw.Formatting = System.Xml.Formatting.Indented; // if you want it indented
                xtw.Indentation = 4;
                xtw.IndentChar = ' ';

                doc.Save(xtw);
                xtw.Flush();
                xtw.Close();
            } // End Using xtw

            doc = null;
        } // End Sub SaveDocument


        public static void ChangeParameterPrompt(string strFilename, string strReportParameterName, string strReplacementText)
        {
            System.Xml.XmlDocument doc = File2XmlDocument(strFilename);
            System.Xml.XmlNamespaceManager nsmgr = GetReportNamespaceManager(doc);

            if (!HasParameter(doc, strReportParameterName))
                return;


            System.Xml.XmlNode xnParameterPrompt = GetParameterPrompt(doc, strReportParameterName);
            string strReportName = System.IO.Path.GetFileNameWithoutExtension(strFilename);

            if (xnParameterPrompt != null)
            {
                string strParameterValue = xnParameterPrompt.FirstChild.Value;
                xnParameterPrompt.FirstChild.Value = strReplacementText;
                LogMessage("Old value in {0}:\t{1}", strReportName, strParameterValue);
            }
            else
                LogMessage("{0}\tKein Parameter " + strReportParameterName, strReportName);

            SaveDocument(doc, strFilename);
        } // End Sub ChangeParameterPrompt


        public static void ChangeStichtag(string strFilename)
        {
            System.Xml.XmlDocument doc = File2XmlDocument(strFilename);
            System.Xml.XmlNamespaceManager nsmgr = GetReportNamespaceManager(doc);

            System.Xml.XmlNode xnStichtag = doc.SelectSingleNode("somequery", nsmgr);
            string strReportName = System.IO.Path.GetFileNameWithoutExtension(strFilename);

            if (!HasParameter(doc, "in_stichtag"))
                return;


            if (xnStichtag != null)
            {
                xnStichtag.FirstChild.Value = "=System.DateTime.Now.ToString(\"dd.MM.yyyy\")";
                string strStichTag = xnStichtag.FirstChild.Value;
                LogMessage("{0}\t{1}", strReportName, strStichTag);
            }
            else
                LogMessage("{0}\tKein Parameter Stichtag", strReportName);

            SaveDocument(doc, strFilename);
        } // End Sub ChangeStichtag



        public static string XmlEscape(string unescaped)
        {
            string strReturnValue = null;

            System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
            System.Xml.XmlNode node = doc.CreateElement("root");
            node.InnerText = unescaped;
            strReturnValue = node.InnerXml;
            node = null;
            doc = null;

            return strReturnValue; 
        } // End Function XmlEscape


        public static string XmlUnescape(string escaped)
        {
            string strReturnValue = null;

            System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
            System.Xml.XmlNode node = doc.CreateElement("root");
            node.InnerXml = escaped;
            strReturnValue = node.InnerText;
            node = null;
            doc = null;

            return strReturnValue;
        } // End Function XmlUnescape





        public static bool HasParameter(System.Xml.XmlDocument doc, string strParameterName)
        {
            strParameterName = XmlEscape(strParameterName);

            System.Xml.XmlNamespaceManager nsmgr = GetReportNamespaceManager(doc);
            System.Xml.XmlNode xnProc = doc.SelectSingleNode("somequery", nsmgr);

            return xnProc != null;
        } // End Function HasParameter




        public static System.Xml.XmlNode GetParameter(System.Xml.XmlDocument doc, string strParameterName)
        {
            strParameterName = XmlEscape(strParameterName);

            System.Xml.XmlNamespaceManager nsmgr = GetReportNamespaceManager(doc);
            System.Xml.XmlNode xnParam = doc.SelectSingleNode("somequery", nsmgr);

            return xnParam;
        } // End Function GetParameter


        public static System.Xml.XmlNode GetParameterPrompt(System.Xml.XmlDocument doc, string strParameterName)
        {
            strParameterName = XmlEscape(strParameterName);

            System.Xml.XmlNamespaceManager nsmgr = GetReportNamespaceManager(doc);
            System.Xml.XmlNode xnParam = doc.SelectSingleNode("somequery", nsmgr);

            return xnParam;
        } // End Function GetParameter


        public static void AddProc(string strFilename)
        {
            System.Xml.XmlDocument doc = File2XmlDocument(strFilename);

            System.Xml.XmlNamespaceManager nsmgr = GetReportNamespaceManager(doc);

            if (HasParameter(doc, "proc"))
                return;

            System.Xml.XmlNode xnMandant = GetParameter(doc, "in_mandant");

            string strReportName = System.IO.Path.GetFileNameWithoutExtension(strFilename);

            if (xnMandant != null)
            {
                LogMessage("{0}\t{1}", strReportName, xnMandant.FirstChild.Value);

                string frag = @"some xml fragment";

                System.Xml.XmlDocumentFragment xmlDocFrag = doc.CreateDocumentFragment();
                xmlDocFrag.InnerXml = frag;

                // System.Xml.XmlNode xn = 
                xnMandant.ParentNode.InsertAfter(xmlDocFrag, xnMandant);
            }
            else
                LogMessage("{0}\tKein Parameter in_mandant", strReportName);

            SaveDocument(doc, strFilename, true);
            //SaveDocument(doc, strFilename, "<ReportParameter Name=\"proc\" xmlns=\"\">", "<ReportParameter Name=\"proc\">");
        } // End Sub AddProc


        public static List<string> GetAllReports(string strPath)
        {
            List<string> ls = new List<string>();
            ls.AddRange(System.IO.Directory.GetFiles(strPath, "*.rdl"));

            return ls;
        } // End Function GetAllReports


        public static void CopyToSaveDirectory(string strFileName)
        {
            string strSavePath = GetSavePath();
            strSavePath = System.IO.Path.Combine(strSavePath, System.IO.Path.GetFileName(strFileName));

            System.IO.File.Copy(strFileName, strSavePath, true);
        } // End Sub CopyToSaveDirectory


        public static void CopyBack(string strFileName)
        {
            string strSavePath = GetSavePath();
            strSavePath = System.IO.Path.Combine(strSavePath, System.IO.Path.GetFileName(strFileName));

            if (System.IO.File.Exists(strSavePath))
            {
                System.IO.File.Copy(strSavePath, strFileName, true); // Exception - Unauthorized access
            }

        } // End Sub CopyBack


        public static void AlterReports(string strPath)
        {
            List<string> lsReports = GetAllReports(strPath);

            foreach (string strFileName in lsReports)
            {
                ChangeStichtag(strFileName);
                CopyBack(strFileName);
                ChangeParameterPrompt(strFileName, "in_standort", "Liegenschaft / Immeuble / Patrimonio immobiliare / Estate");
                CopyBack(strFileName);
                ChangeParameterPrompt(strFileName, "in_gebaeude", "Gebäude / Bâtiment / Edificio / Building");
                CopyBack(strFileName);
                ChangeParameterPrompt(strFileName, "in_geschoss", "Geschoss / Étage / Piano / Floor");
                CopyBack(strFileName);
                ChangeParameterPrompt(strFileName, "in_trakt", "Trakt / Aile / Ala / Wing");
                CopyBack(strFileName);
                ChangeParameterPrompt(strFileName, "in_haus", "Haus / Maison / Casa / House");
                CopyBack(strFileName);
                ChangeParameterPrompt(strFileName, "in_raum", "Raum / Pièce / Stanza / Room");
                CopyBack(strFileName);
                ChangeParameterPrompt(strFileName, "in_stichtag", "Stichtag / Jour de référence / Giorno di riferimento / Reporting date");
                CopyBack(strFileName);
                ChangeParameterPrompt(strFileName, "in_mietertrag", "Mindestertrag Mindestertrag / Rendement minimum / Rendimento minimo / Minimum yield");
                CopyBack(strFileName);
            } // Next strFileName

        } // End Sub InvestigateStichtag


        /// <summary>
        /// Der Haupteinstiegspunkt für die Anwendung.
        /// </summary>
        [STAThread]
        static void Main()
        {
            string strPath = @"S:\SomeBody\SomeFolder\Reports";

            AlterReports(strPath);

            Console.WriteLine(Environment.NewLine);
            Console.WriteLine(" --- Press any key to continue --- ");
            Console.ReadKey();
        } // End Sub Main


    } // End Class Program


} // End Namespace ReportModifier
Was it helpful?

Solution 2

Never mind.
The problem was the files were SSRS reports.
I copied them from the report solution folder (under source control) to another folder for experimentation.
But the WriteProtected flag on the files gets copied together with the files.
Did edit and save one in visual studio, to see if I have permission to write on them.
That removed the write protection, which resolved the problem.

So you have to do a:

if(FileIsWriteProtected)
    Unprotect(file);

System.IO.File.Copy(Source, file.FullPath, true);

Incidentially, that also explains why I got an UnauthorizedAccessException.

OTHER TIPS

Looking at this code:

public static void CopyBack(string strFileName)
{
    string strSavePath = GetSavePath();
    strSavePath = System.IO.Path.Combine(strSavePath, System.IO.Path.GetFileName(strFileName));

    if (System.IO.File.Exists(strSavePath))
    {
        System.IO.File.Copy(strSavePath, strFileName, true); // Exception - Unauthorized access
    }
}

It appears that you intend to copy the file from strFileName to the folder specified by GetSavePath().

If this indeed is the case, then be aware that you have the parameters for File.Copy() the wrong way around.

It's Copy(String sourceFileName, string destFileName, bool overwrite)

So in that case your code should be:

System.IO.File.Copy(strFileName, strSavePath, true);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top