Ticket T379035
Visible to All Users

How to display XAF file attachments (e.g., a PDF document stored via FileData) in non XAF web site

created 9 years ago

Hello,

I am trying to use XAF as an administration tool to store PDF documents in the database using the FileData table. My hope is that there is a way to extract that document when a user clicks on a hyperlink (preferably) or a button and opens that document in a new tab in the browser. The website this needs to display in is a standard .net web application and not an XAF website.

I was able to create the following but the Content Field apparently has additional information at the beginning of the file and corrupts the PDF when created. Also it downloads instead of opening in a new browser.

Thanks for your help!

var btn = (ASPxButton)sender;
        var arg = btn.CommandArgument;

string connetionString = myConnection ;
        string sql = "SELECT  [Content] FROM [dbo].[FileData]  WHERE [FileName] = '" + arg + "'";

var cnn = new SqlConnection(connetionString);
        try
        {
            cnn.Open();
            var cmd = new SqlCommand(sql, cnn);
            var reader = cmd.ExecuteReader();
            while (reader.Read())
            {
                Response.Buffer = true;
                Response.Charset = "";
                Response.AppendHeader("Content-Disposition", "attachment; filename=" + arg);
                Response.Cache.SetCacheability(HttpCacheability.NoCache);
                Response.ContentType = "application/pdf";
                Response.BinaryWrite(reader.GetValue(1) as byte[]);
                Response.Flush();
                Response.End();
            }
            reader.Close();
            cmd.Dispose();
            cnn.Close();
        }
        finally
        {
            cnn.Close();
        }

Answers approved by DevExpress Support

created 9 years ago (modified 6 years ago)

Hello,

You cannot reuse the FileData.Content property directly, because according to https://documentation.devexpress.com/#eXpressAppFramework/CustomDocument112781 "When using the  *FileData type,  *gzip compression is applied and the maximum file size is 4 gigabytes."

To extract a compressed value, it is necessary to use the IFileData.SaveToStream method. That means that on your non-XAF website, you will need to reference the assembly containing the FileData type (e.g., DevExpress.Persistent.BaseImpl for XPO) and its dependencies, retrieve a required FileData instance from the database using the XPO's Session (learn more…) or XAF's IObjectSpace (learn more…) and then call its SaveToStream method to save its content into a MemoryStream or other Stream objects. To learn more about our custom compression mechanism, research the …\DevExpress.Persistent\DevExpress.Persistent.BaseImpl\CompressionUtils.cs source code.

If you wish attachments in your database to be easily accessed by non-XAF applications, you can implement your own class to store attachments similar to FileData but without compression. You can do this by copying the FileData class source code from the …\XAF\DevExpress.Persistent\DevExpress.Persistent.BaseImpl\FileData.cs file, renaming the class in it as you want and finally by removing the ValueConverter(typeof(CompressionConverter)) attribute from its Content property.

    Show previous comments (2)
    BA BA
    Bassam Abdelaal 6 years ago

      Hello Dennis,

      cant we use a standard method to extract gzip files and so work with FileData.Content directly ?
      like example 4 here :

      https://docs.microsoft.com/en-us/dotnet/standard/io/how-to-compress-and-extract-files

      or XAF is using custom compression ?

      Thanks

      Dennis Garavsky (DevExpress) 6 years ago

        @Bassam: No, XAF uses a custom compression algorithm: …\DevExpress.Persistent\DevExpress.Persistent.BaseImpl\CompressionUtils.cs

          I solve with this.

          C#
          //Usage. content = DataRow column public static byte[] ConvertOleObjectToByteArrayXaf(object content) { if (content != null && !(content is DBNull)) { using (MemoryStream ms = new MemoryStream()) { return CompressionUtils.Decompress(new MemoryStream((byte[])content)).ToArray(); } } return null; } //Simplified from original public class CompressionUtils { private static Guid Version2Prefix = new Guid("DA088B12-6641-413b-BBFC-2829752DCF96"); private const string Version2XafCompressedYesString = "+"; private const string Version2XafCompressedNoString = "-"; private const int MinAlwaysCompressedLenght = 1000000; private static MemoryStream DecompressData(MemoryStream ms) { int BufferSize = 5196; MemoryStream result = new MemoryStream(); using (GZipStream inStream = new GZipStream(ms, CompressionMode.Decompress, true)) { byte[] buffer = new byte[BufferSize]; while (true) { int readCount = inStream.Read(buffer, 0, BufferSize); if (readCount == 0) { break; } result.Write(buffer, 0, readCount); } } return result; } private static MemoryStream DecompressVersion2Stream(MemoryStream ms) { byte[] header = new byte[System.Text.Encoding.UTF8.GetBytes(Version2XafCompressedYesString.ToCharArray()).Length]; ms.Read(header, 0, header.Length); string headerString = System.Text.Encoding.UTF8.GetString(header, 0, header.Length); if (headerString == Version2XafCompressedYesString) { return DecompressData(ms); } if (headerString == Version2XafCompressedNoString) { MemoryStream result = new MemoryStream(); while (ms.Position < ms.Length) { result.WriteByte((byte)ms.ReadByte()); } return result; } throw new ArgumentException(); } public static MemoryStream Decompress(MemoryStream data) { if (data != null && data.Length > 0) { long startPosition = data.Position; byte[] guidPrefix = new byte[16]; data.Read(guidPrefix, 0, guidPrefix.Length); if (new Guid(guidPrefix) == Version2Prefix) { return DecompressVersion2Stream(data); } else { data.Position = startPosition; return DecompressData(data); } } return data; } }

          Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

          Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.