BETA
Aby się zalogować, najpiew wybierz portal.
Aby się zarejestrować, najpiew wybierz portal.
Podaj słowa kluczowe
Słowa kluczowe muszą mieć co najmniej 3 sąsiadujące znaki alfanumeryczne
Pole zawiera niedozwolone znaki

Baza wiedzy











Drukowanie raportów Microsoft.ReportingServices 2005

31-01-2006 23:10 | radzimskik
Masowe drukowanie raportów bez okien dialogowych i podglądów

Wprowadzenie

W Microsoft ReportingServices 2005 jest prawie wszystko co chcemy i zapewne milion rzeczy o których nie mamy zielonego pojęcia.
Podstawowe zagadnienia przybliżył już kolega
Piotr Pałka w artykule "Usługi raportujące w SQL Server 2005"
Jednak na próżno jest szukać metody Print() która pozwoliła by drukować dokumenty bez potrzeby ich wyświetlania w oknie podglądu.
Za pomocą kontrolki reportViewer możemy wyświetlić standardowy dialog drukowania.

[Kod C#]

reportViewer1.PrintDialog();

Takie rozwiązanie ma jednak tę wadę, że zmuszamy użytkownika do obsługi okna dialogowego. W przypadku drukowania całej serii dokumentów, faktur itp. czynność ta będzie powtarzana wielokrotnie. Trzeba też wziąć po uwagę użytkowników, którzy nie powinni w ogóle zastanawiać się ile i gdzie drukują (np. magazynierzy, pracownicy zakładów produkcyjnych itd.)

Szczytem szczęścia byłoby więc wydrukowanie raportu za pomocą metody

void Print(string path, string parameters, string printername, int copies);

Jak to zrobić ?

WebReference do serwera raportowego

Po pierwsze tworzymy WebReference do naszego serwera raportowego.

WebReference_RS2005.PNG

Interfejs IReport

Definiujemy interfejs IReport

[Kod C#]

public interface IReport
{
void Print(string path, string parameters, string printername, int copies, string host);
void Print(string path, string parameters, string printername, int copies);
void Print(string path, string parameters, string printername);
void Print(string path, string printername, int copies);
void Print(string path, string printername);
}

Klasa ReportController

Implementujemy interfejs w klasie ReportController

[Kod C#]

public class ReportController : IReport
{
private static
ReportRender reportRender = new ReportRender();
public static string ReportServerHost =
"";

#region IReport Members

/// <summary>
///
Wydrukowanie raportu
/// </summary>
///
<param name="path">Ścieżka do raportu np./Folder/RaportName</param>
///
<param name="printername">Nazwa drukarki</param>
public void Print(string path, string printername)
{
  Print(path,
"", printername, 2);
}

/// <summary>
///
Wydrukowanie raportu
/// </summary>
///
<param name="path">Ścieżka do raportu np./Folder/RaportName</param>
///
<param name="printername">Nazwa drukarki</param>
///
<param name="copies">Ilość kopii</param>
public void Print(string path, string printername, int copies)
{
  Print(path,
"", printername, copies);
}

/// <summary>
///
Wydrukowanie raportu
/// </summary>
///
<param name="path">Ścieżka do raportu np./Folder/RaportName</param>
///
<param name="parameters">Parametry raportu</param>
///
<param name="printername">Nazwa drukarki</param>
public void Print(string path, string parameters, string printername)
{
  Print(path, parameters, printername, 2);
}

/// <summary>
///
Wydrukowanie raportu
/// </summary>
///
<param name="path">Ścieżka do raportu np./Folder/RaportName</param>
///
<param name="parameters">Parametry raportu</param>
///
<param name="printername">Nazwa drukarki</param>
///
<param name="copies">Ilość kopii</param>
public void Print(string path, string parameters, string printername, int copies)
{
  Print(path, parameters, printername, copies, ReportServerHost);
}

#region IReport Members - Obsługa innego hosta
/// <summary>
///
Wydrukowanie raportu
/// </summary>
///
<param name="path">Ścieżka do raportu np./Folder/RaportName</param>
///
<param name="parameters">Parametry raportu</param>
///
<param name="printername">Nazwa drukarki</param>
///
<param name="copies">Ilość kopii</param>
///
<param name="host">Serwer raportowy - nazwa hosta</param>
public void Print(string path, string parameters, string printername, int copies, string host)
{
 try{
 reportRender.RenderToPrinter(path, parameters, printername, copies, host);
 }
 catch (
Exception ex)
 {
 
MessageBox.Show("Nie można wygenerować raportu.\r\n\r\n" + ex.Message,
 
Assembly.GetCallingAssembly().GetName().Name,MessageBoxButtons.OK,MessageBoxIcon.Error);
 }
}
#endregion
}

Skoro kwestie organizacyjne mamy za sobą to możemy przejść do właściwego kodu drukującego raport.
Zapewne zauważyłeś, że całość realizuje klasa reportRender i jej metoda RenderToPrinter.
Do metody tej należy przekazać ścieżkę do raportu w formacie "/Folder/Nazwa_Raportu", parametry w postaci "Nazwa_Parametru1,Wartość_1,Nazwa_Parametru2,Wartość_2...", Nazwę drukarki, Ilość kopii i adres hosta naszego serwera raportowego.

taki a nie inny zapis parametrów pozwala na skorzystanie z metody w dowolnie starym środowisku programowania, który potrafi korzystać z bibliotek typów (np. stare dobre Delphi < 8)

Korzystanie z wielu serwerów ReportingServices

W szczególności możemy korzystać z serwera ReportingServices 2003 i 2005 za pomocą tych samych wywołań.
Tak na marginesie to z moich testów wynika że renderowanie raportu na Sql2005 trwa do trzech razy krócej niż tego samego raportu na ReportingServices dla Sql2000.

Podmiana nazwy hosta z naszej WebReference do serwera raportowego realizuje klasa przedstawiona poniżej.

[Kod C#]

public class ReportServerConnector : FrameworkReportService.ReportingService

    {

        /// <summary>

        /// Konstruktor klasy ReportServerConnector

        /// </summary>

        /// <param name="host">Nazwa hosta Reporting Services</param>

        public ReportServerConnector(string host)

        {

            if (host != "")

            {

                this.Url = "http://" + host.ToString() + "/reportserver/reportservice.asmx?wsdl";

            }

            else

            {

                this.Url = "http://" + ReportController.ReportServerHost.ToString()

                  + "/reportserver/reportservice.asmx?wsdl";

            }

        }

 

        /// <summary>

        /// Nadpisanie procedury GetWebRequest(Uri uri).

        /// </summary>

        /// <remarks>

        /// Ta procedura zapobiera powstaniu błędu

        /// System.Net.WebException: The underlying connection was closed:

        /// An unexpected error occurred on a send.

        /// </remarks>

        /// <param name="uri">adres uri.</param>

        /// <returns>Obiekt WebRequest.</returns>

        protected override System.Net.WebRequest GetWebRequest(Uri uri)

        {

            System.Net.HttpWebRequest webRequest =

                (System.Net.HttpWebRequest)base.GetWebRequest(uri);

            webRequest.KeepAlive = false;

            webRequest.ProtocolVersion = HttpVersion.Version11;

           

            System.Net.WebProxy proxy = new WebProxy("myproxy",8080);

            proxy.BypassProxyOnLocal = true;

 

            webRequest.Proxy = proxy;

            return webRequest;

        }

    }

 

Klasa renderujaca ReportRender

Tworzymy interfejs IReportRender

[Kod C#]

    /// <summary>

    /// Interfejs klasy odpowiedzialny za wydrukowanie raportu ReportingServices

    /// Dla zadanego raportu, wg zadanego kryterium

    /// </summary>

    public interface IReportRender

    {

        /// <summary>

        /// Wyrenderowanie raportu na drukarkę

        /// </summary>

        /// <param name="path">Ściezka do raportu</param>

        /// <param name="parameters">Parametry raportu</param>

        /// <param name="printername">Nazwa drukarki</param>

        /// <param name="copies">Ilość kopii</param>

        /// <param name="host">Nazwa serwera</param>

        void RenderToPrinter(string path, string parameters, string printername, int copies, string host);

 

        /// <summary>

        /// Wyrenderowanie raportu na drukarkę

        /// </summary>

        /// <param name="path">Ściezka do raportu</param>

        /// <param name="parameters">Parametry raportu</param>

        /// <param name="printername">Nazwa drukarki</param>

        /// <param name="copies">Ilość kopii</param>

        /// <param name="host">Nazwa serwera</param>

        /// <param name="username">Nazwa użytkownika</param>

        /// <param name="password">Hasło</param>

        /// <param name="domain">Nazwa domeny</param>

        void RenderToPrinter(string path, string parameters, string printername, int copies, string host,

            string username, string password, string domain);

 

    }

A następnie implementujemy w klasie ReportRender

[Kod C#]

    /// <summary>

    /// Klasa odpowiedzialna za wydrukowanie raportu ReportingServices

    /// Dla zadanego raportu, wg zadanego kryterium

    /// </summary>

    public class ReportRender : IReportRender

    {

 

        #region IReportRender Members

        /// <summary>

        /// Wyrenderowanie raportu na drukarkę

        /// </summary>

        /// <param name="path">Ściezka do raportu</param>

        /// <param name="parameters">Parametry raportu</param>

        /// <param name="printername">Nazwa drukarki</param>

        /// <param name="copies">Ilość kopii</param>

        /// <param name="host">Nazwa serwera</param>

        public void RenderToPrinter(string path, string parameters

, string printername, int copies, string host)

        {

 

            #region Zamiana parametru string na tablice ParameterValue

            Array lista = null;

            ParameterValue[] rp = null;

            if (parameters.Trim() != "")

            {

                char[] sep = { ',' };

                lista = parameters.Split(sep);

                int wymiar = lista.Length / 2;

 

                rp = new ParameterValue[wymiar];

 

                int j = 0;

                for (int i = 0; i < lista.Length - 1; i = i + 2)

                {

                    rp[j] = new ParameterValue();

                    rp[j].Name = lista.GetValue(i).ToString();

                    rp[j].Value = lista.GetValue(i + 1).ToString();

                    j++;

                }

            }

            #endregion

 

            //Wywołujemy metodę ustawiającą parametry aplikacji

            this.SetParameters(host, path, copies);

 

            //Wywołujemy metodę drukującą raport

            _RenderedReport = this.RenderPrintReport(rp);

 

            if (_PagesOf < 1)

                return;

            //Ustawiamy opcje drukarki

            PrinterSettings _PrinterSettings = new PrinterSettings();

            _PrinterSettings.MaximumPage = _PagesOf;

            _PrinterSettings.MinimumPage = 1;

            _PrinterSettings.PrintRange = PrintRange.SomePages;

            _PrinterSettings.FromPage = 1;

            _PrinterSettings.ToPage = _PagesOf;

            _PrinterSettings.PrinterName = printername;

           

            PrintDocument pd = new PrintDocument();

            _CurrentPrintingPage = 1;

            _LastPrintingPage = _PagesOf;

            pd.PrinterSettings = _PrinterSettings;

 

            pd.PrintPage += new PrintPageEventHandler(this.pd_PrintPage);

            pd.PrinterSettings.Copies = _PrintCopies;

            pd.PrintController = new StandardPrintController();

 

            if (lista != null)

            {

                pd.DocumentName = lista.GetValue(1).ToString();

            }

            else

            {

                pd.DocumentName = path.Replace("/", "_").Trim();

            }

 

            pd.Print();

        }

 

        /// <summary>

        /// Wyrenderowanie raportu na drukarkę

        /// </summary>

        /// <param name="path">Ściezka do raportu</param>

        /// <param name="parameters">Parametry raportu</param>

        /// <param name="printername">Nazwa drukarki</param>

        /// <param name="copies">Ilość kopii</param>

        /// <param name="host">Nazwa serwera</param>

        /// <param name="username">Nazwa użytkownika</param>

        /// <param name="password">Hasło</param>

        /// <param name="domain">Nazwa domeny</param>

        public void RenderToPrinter(string path, string parameters

, string printername, int copies, string host

, string username, string password, string domain)

        {

            _UserName = username;

            _Password = password;

            _Domain = domain;

            RenderToPrinter(path, parameters, printername, copies, host);

        }

        #endregion

 

        #region Zmienne prywatne klasy

 

        private ReportServerConnector _RepServices = null;

        //Nazwa raportu

        private string _ReportName = null;

 

        private byte[][] _RenderedReport;

        private int _PagesOf;

        private int _CurrentPrintingPage;

        private int _LastPrintingPage;

        private Graphics.EnumerateMetafileProc _Delegate = null;

        private MemoryStream _CurrentPagesStream;

        private Metafile _MetaFile = null;

        private short _PrintCopies = 2;

        private string _UserName = null;

        private string _Password = null;

        private string _Domain = null;

 

        #endregion

 

        #region Metoda - Ustawienie parametrów raportu

        /// <summary>

        /// Ustawienie parametrów raportu

        /// </summary>

        /// <param name="aHost">Nazwa serwera usługi ReportingServices</param>

        /// <param name="aReportName">Nazwa raportu</param>

        /// <param name="aParamName">Nazwa parametru raportu ReportingServices</param>

        /// <param name="aParamValue">Wartość parametru</param>

        /// <param name="aCopies">Liczba kopii</param>

        private void SetParameters(string aHost,

string aReportName, int aCopies)

        {

            _RepServices = new ReportServerConnector(aHost);

            //Gdy liczba kopii przekazana jako 0          

            if (aCopies > 0)

            {

                _PrintCopies = (short)aCopies;

            }

            _ReportName = aReportName;

            this.SecurityCredentials();

        }

 

        #endregion

 

        #region Metody odpowiedzialne za drukowanie

        private byte[][] RenderPrintReport(

ParameterValue[] aReportParameters)

        {

            string _deviceInfo = null;

            string _format = "IMAGE";

            string _encoding;

            string _mimeType;

            Warning[] _warnings = null;

            ParameterValue[] _reportHistoryParameters = null;

            string[] _streamIDs = null;

 

            Byte[][] _pages = null;

            Byte[] _firstPage = null;

 

            int i = 0;

            _deviceInfo = String.Format(@"<DeviceInfo><OutputFormat>{0}

                                 </OutputFormat></DeviceInfo>", "emf");

            _firstPage = _RepServices.Render(_ReportName, _format, null, _deviceInfo, aReportParameters,

                null, null, out _encoding, out _mimeType, out _reportHistoryParameters,

                out _warnings, out _streamIDs);

            //Liczba wszystkich stron raportu pierwsza plus to co jest w strumieniu

            _PagesOf = _streamIDs.Length + 1;         

            _pages = new byte[_PagesOf][];

            _pages[0] = _firstPage;        

 

            for (int pageindex = 1 + i; pageindex < _PagesOf; pageindex++)

            {

                _deviceInfo =

            String.Format(@"<DeviceInfo><OutputFormat>{0}

                           </OutputFormat><StartPage>{1}

                           </StartPage></DeviceInfo>", "emf", pageindex + 1);

                _pages[pageindex] = _RepServices.Render(_ReportName, _format, null

                                       , _deviceInfo, aReportParameters,

                    null, null, out _encoding, out _mimeType, out _reportHistoryParameters,

                    out _warnings, out _streamIDs);

            }

            return _pages;

        }

 

        private void pd_PrintPage(object sender, PrintPageEventArgs aPrintPageEventArgs)

        {

            aPrintPageEventArgs.HasMorePages = false;

            if (_CurrentPrintingPage <= _LastPrintingPage && MoveToPage(_CurrentPrintingPage))

            {

                ReportDrawPage(aPrintPageEventArgs.Graphics);

 

                if (++_CurrentPrintingPage <= _LastPrintingPage)

                    aPrintPageEventArgs.HasMorePages = true;

            }

        }

 

        private void ReportDrawPage(Graphics aGraphics)

        {

            if (null == _CurrentPagesStream || 0 == _CurrentPagesStream.Length || null == _MetaFile)

                return;

            lock (this)

            {              

                int width = _MetaFile.Width;

                int height = _MetaFile.Height;

                _Delegate = new Graphics.EnumerateMetafileProc(MetafileCallback);

 

                Point[] points = new Point[3];

                Point destPoint = new Point(0, 0);

                Point destPoint1 = new Point(width, 0);

                Point destPoint2 = new Point(0, height);

 

                points[0] = destPoint;

                points[1] = destPoint1;

                points[2] = destPoint2;

                aGraphics.InterpolationMode = InterpolationMode.Low;

                aGraphics.CompositingQuality = CompositingQuality.HighSpeed;

                aGraphics.EnumerateMetafile(_MetaFile, points, _Delegate);

                _Delegate = null;

            }

        }

 

        private bool MoveToPage(Int32 page)

        {

            if (null == _RenderedReport[_CurrentPrintingPage - 1])

                return false;

            _CurrentPagesStream = new MemoryStream(_RenderedReport[_CurrentPrintingPage - 1]);

            _CurrentPagesStream.Position = 0;

            if (null != _MetaFile)

            {

                _MetaFile.Dispose();

                _MetaFile = null;

            }

            _MetaFile = new Metafile((Stream)_CurrentPagesStream);

            return true;

        }

 

        private bool MetafileCallback(EmfPlusRecordType recordType

         , int flags, int dataSize, IntPtr data, PlayRecordCallback callbackData)

        {

            byte[] dataArray = null;        

            if (data != IntPtr.Zero)

            {       

                dataArray = new byte[dataSize];

                Marshal.Copy(data, dataArray, 0, dataSize);

            }   

            _MetaFile.PlayRecord(recordType, flags, dataSize, dataArray);

            return true;

        }

 

        #endregion

 

        #region   Uwierzytelnianie w usłudze ReportingServices

 

        /// <summary>

        /// Uwierzytelnianie w usłudze ReportingServices

        /// </summary>

        private void SecurityCredentials()

        {

            if (_UserName == null)

            {

                _RepServices.Credentials = CredentialCache.DefaultCredentials;

            }

            else

            {

                System.Net.NetworkCredential credentials =

                  new System.Net.NetworkCredential(_UserName, _Password, _Domain);

                _RepServices.Credentials = credentials;

            }

        }

        #endregion     

 

    }

Jak widać, cała operacja jest prosta i polega na wyrenderowaniu raportu do metapliku EMF (właściwie strumienia) i wydrukowaniu strona po stronie.
Mam nadzieję że ten artykuł nie jest zbyt zawiły i pomoże Ci stworzyć własne szybki narzędzie do masowego drukowania raportów.

Ps.
Ponieważ jest to mój pierwszy artykuł to proszę o wyrozumiałość:)

 

Podobne artykuły

Komentarze 0

pkt.

Zaloguj się lub Zarejestruj się aby wykonać tę czynność.