# Resources Customization

The Custom Resource Locator sample demonstrates a custom resource locator that looks for files in the current user’s MyPictures folder by looking for a special MyPictures protocol.

## Content



Reports can depend on external resources. ActiveReports provides the possibilities to resolve reporting tasks, related to using any resources that your report may require. With the ActiveReports [custom resource locator](/activereportsnet/docs/v19.2/developers/extensibility-in-activereports/custom-resource-locator), you can place any resources - themes, image files, subreports, CSS, etc, to any location in your file system.

In ActiveReports, you can place resources such as themes, image files, subreports, CSS, to any location with some exceptions:

*   Section report requires using scripts to bind subreports.
*   Some data source types require using connection strings with absolute paths.

Page and RDLX reports can resolve resources from your file system using file paths, but sometimes resources are preserved in very specific sources, such as a database. With RDLX report, you can create a custom resource locator to read any resources that might be required by your reports from any type of location. You can use it for resources such as images and theme files, or for reports to use in drillthrough links, subreports, or master reports.

The [Custom Resource Locator](https://github.com/activereports/Samples19/tree/main/Advanced/PageAndRDLX/CustomResourceLocator) sample demonstrates a custom resource locator that looks for files in the current user’s **My Pictures** folder by looking for a special MyPictures protocol. The custom resource locator in the sample is implemented by deriving from GrapeCity.ActiveReports.ResourceLocator class and overriding the [GetResource](/activereportsnet/api/v19.2/MESCIUS.ActiveReports.Core.Rdl/GrapeCity.ActiveReports.ResourceLocator.html) method. The **GetResource** method returns [ParentUri](/activereportsnet/api/v19.2/MESCIUS.ActiveReports.Core.Rdl/GrapeCity.ActiveReports.Resource.html) and [Value](/activereportsnet/api/v19.2/MESCIUS.ActiveReports.Core.Rdl/GrapeCity.ActiveReports.Resource.html) properties. The **Value** property contains the located resource as a memory stream. The **ParentUri** property contains the string URI of the parent of the resource within the resource hierarchy.

You can customize the resource locator for all report types in the following ActiveReports components:

*   Windows Forms Designer and Windows Forms Viewer
*   WPF Viewer
*   all ASP.NET viewer backends
*   all exports

See the [ResourceLocator](/activereportsnet/api/v19.2/MESCIUS.ActiveReports/GrapeCity.ActiveReports.PageReport.html#RESOURCELOCATOR) property for details.


> type=note
> **Note**: The WebDesigner uses a completely different mechanism to access resources. See the [WebDesigner\_CustomStore](https://github.com/activereports/WebSamples19/tree/main/WebDesigner_CustomStore) sample for details.

## Load Pictures from My Pictures directory

Page reports can get resources from your file system using file paths, but sometimes resources are preserved in very specific sources, such as a database. With Page reports, you can create a custom resource locator to read any resources that might be required by your reports from any location.

The following steps illustrate how to load pictures from the user's **My Pictures** or **Pictures** directory based on the [Custom Resource Locator](https://github.com/activereports/Samples19/tree/main/Advanced/PageAndRDLX/CustomResourceLocator) sample.


> type=note
> **Note**: Although these steps use Page reports, you can also implement this using RDLX reports.

When you complete these steps, you get a layout that looks similar to the following at run time.

![Custom Resource Locator](https://cdn.mescius.io/document-site-files/images/b298aea2-8cb8-4a0f-be88-4f54aa263ebd/images/wlk_page_customresourcelocator_runtime.jpg)

### Add an ActiveReports to the Visual Studio project

1.  Create a new Visual Studio Windows Forms Application project.
2.  Go to the Project Explorer, right-click the project and select **Add** > **New Item.**
3.  Select **ActiveReports 19 Standalone Report** > **Add** and choose a report type, **Page** report and then click **Finish**.
4.  In the Name field, rename the file as DemoReport.rdlx.
5.  Click the **Add** button to open a new Page Report.

### Create a layout for the report

1.  From the toolbox, drag an [Image](/activereportsnet/docs/v19.2/report-authors/report-controls/report-controls-page-rdl-report/image) control onto the design surface and in the Properties panel, set the following properties.
    
    | Property Name | Property Value |
    | --- | --- |
    | Name | Image1 |
    | Location | 0.1in, 0.1in |
    | Size | 2.8in, 2.8in |
    | Value | MyPictures:Penguins.jpg |
    
2.  From the toolbox, drag another [Image](/activereportsnet/docs/v19.2/report-authors/report-controls/report-controls-page-rdl-report/image) control onto the design surface and in the Properties panel, set the following properties.
    
    | Property Name | Property Value |
    | --- | --- |
    | Name | Image2 |
    | Location | 3.1in, 0.1in |
    | Size | 2.8in, 2.8in |
    | Value | MyPictures:Desert.jpg |
    
3.  In the Solution Explorer, select DemoReport.rdlx and in the Properties panel, set **Build Action** to **Embedded Resource**.

### Add the new MyPicturesLocator class

1.  In the Solution Explorer window, right-click on your project name and select **Add** and then **New Item**.
2.  In the **Add New Item** dialog that appears, select **Class**.
3.  Change the name of the class to **MyPicturesLocator** and click the **Add** button.
4.  Replace the existing code with the following code to the new class.
    
    To write the code in Visual Basic.NET
    
    ```vbnet
    Imports System                                                     
    Imports System.Drawing
    Imports GrapeCity.ActiveReports.Extensibility
    Imports System.Globalization
    Imports System.IO
    Imports System.Runtime.InteropServices
    ```
    
    ```vbnet
    Inherits ResourceLocator
    
        Private Const UriSchemeMyImages As String = "MyPictures:"
    
        ' Obtain and return the resource.     
        Public Overrides Function GetResource(resourceInfo As ResourceInfo) As Resource
            Dim name As String = resourceInfo.Name
            If name Is Nothing OrElse name.Length = 0 Then
                Throw New ArgumentException("The name of resource to be obtained should be non-empty string.", "name")
            End If
            Dim uri As New Uri(name)
            Dim stream As Stream = GetPictureFromSpecialFolder(name)
            If stream Is Nothing Then
                stream = New MemoryStream()
            End If
            Return New Resource(stream, uri)
        End Function
    
        ' Returns the specified image from Public Pictures folder. 
        Private Shared Function GetPictureFromSpecialFolder(path As String) As Stream
            Dim startPathPos As Integer = UriSchemeMyImages.Length
            If startPathPos >= path.Length Then
                Return Nothing
            End If
            Dim pictureName As String = path.Substring(startPathPos)
            Dim myPicturesPath As String = Environment.GetEnvironmentVariable("public") & "\Pictures"
            If Not myPicturesPath.EndsWith("\") Then
                myPicturesPath += "\"
            End If
            Dim picturePath As String = System.IO.Path.Combine(myPicturesPath, pictureName)
            If Not File.Exists(picturePath) Then
                Return Nothing
            End If
            Dim stream As New MemoryStream()
            Try
                Dim picture As Image = Image.FromFile(picturePath)
                picture.Save(stream, picture.RawFormat)
                stream.Position = 0
            Catch generatedExceptionName As OutOfMemoryException
                ' The file is not valid image, or GDI+ doesn't support such images.
                Return Nothing
            Catch generatedExceptionName As ExternalException
                Return Nothing
        End Try
        Return stream
    End Function
    ```
    
    To write the code in C#
    
    ```csharp
    using System; 
    using System.Drawing; 
    using System.Globalization;
    using System.IO; 
    using System.Runtime.InteropServices; 
    using System.Windows.Forms;
    using GrapeCity.ActiveReports.Extensibility; 
    using your_project_name.Properties;
    ```
    
    ```csharp
    namespace your_project_name
    {
        // Look for the resources in My Pictures folder.   
        internal sealed class MyPicturesLocator : ResourceLocator
        {        
            private const string UriSchemeMyImages = "MyPictures:";
            // Obtain and return the resource.     
            public override Resource GetResource(ResourceInfo resourceInfo)
            {
                string name = resourceInfo.Name;
                if (name == null || name.Length == 0)
                {
                    throw new ArgumentException("The name of resource to be obtained should be non-empty string.", "name");
                }
                Uri uri = new Uri(name);
                Stream stream = GetPictureFromSpecialFolder(name);
                if (stream == null)
                {
                   stream = new MemoryStream();
                }
                return new Resource(stream, uri);
            }
            // Returns the specified image from Public Pictures folder. 
            private static Stream GetPictureFromSpecialFolder(string path)
            {
                int startPathPos = UriSchemeMyImages.Length;
                if (startPathPos >= path.ToString().Length)
                {
                    return null;
                }
                string pictureName = path.ToString().Substring(startPathPos);
                string myPicturesPath = Environment.GetEnvironmentVariable("public") + \\Pictures;
                if (!myPicturesPath.EndsWith("\\")) myPicturesPath += "\\";
                string picturePath = Path.Combine(myPicturesPath, pictureName);
                            if (!File.Exists(picturePath)) return null;
                MemoryStream stream = new MemoryStream();
                try
                {
                    Image picture = Image.FromFile(picturePath);
                    picture.Save(stream, picture.RawFormat);
                    stream.Position = 0;
                }
                catch (OutOfMemoryException) // The file is not valid image, or GDI+ doesn't support such images. 
                {
                    return null;
                }
                catch (ExternalException)
                {
                    return null;
                }
                return stream;
            }
        }
    }
    ```
    

### Create the PreviewForm

1.  In the Solution Explorer, select the Form1 in the Design view and in the Properties panel, set the properties as follows.
    
    | Property Name | Property Value |
    | --- | --- |
    | Name | PreviewForm |
    | Text | Preview Form |
    | Size | 1015, 770 |
    
2.  From the Visual Studio toolbox, drag the Viewer control onto the PreviewForm and in the Properties panel, set the following properties.
    
    | Property Name | Property Value |
    | --- | --- |
    | Name | reportPreview1 |
    | Dock | Fill |
    
3.  Double-click the PreviewForm to create an instance for the Load event and add the following code.
    
    To write the code in Visual Basic.NET
    
    ```vbnet
    Imports GrapeCity.ActiveReports.Document
    Imports System.IO 
    Imports GrapeCity.ActiveReports
    ```
    
    ```vbnet
    Dim myPicturesPath As String = Environment.GetEnvironmentVariable("public") + _PicturesDim reportData As Stream = [GetType](/activereportsnet/docs/v19.2/developers/extensibility-in-activereports/custom-resource-locator).Assembly.GetManifestResourceStream("your_project_name.DemoReport.rdlx")
    reportData.Position = 0
    Dim reader As New StreamReader(reportData)
    Dim def As New PageReport(reader)
    def.ResourceLocator = New MyPicturesLocator()
    Dim runtime As New PageDocument(def)
    reportPreview1.ReportViewer.LoadDocument(runtime)
    ```
    
    To write the code in C#
    
    ```csharp
    using GrapeCity.ActiveReports.Document; 
    using System.IO;
    using GrapeCity.ActiveReports;
    ```
    
    ```csharp
    string myPicturesPath = Environment.GetEnvironmentVariable("public") + \\Pictures;
    Stream reportData = GetType().Assembly.GetManifestResourceStream("your_project_name.DemoReport.rdlx");
    reportData.Position = 0;
    StreamReader reader = new StreamReader(reportData);
    PageReport def = new PageReport(reader);
    def.ResourceLocator = new MyPicturesLocator();
    PageDocument runtime = new PageDocument(def);
    reportPreview1.ReportViewer.LoadDocument(runtime);
    ```
    
4.  Press **F5** to run the project.

## See Also

[Caching Reports](/activereportsnet/docs/v19.2/developers/create-applications/js-viewer-application/caching-reports)