none
Within SharePoint2013 environment, how to have an .aspx page use code residing in a separate .cs file RRS feed

  • Question

  • I am a long-time ASP.NET programmer being asked to change some .aspx code that runs within SharePoint 2013.

    Unlike most standard .aspx pages, there is no code-behind file for "Report.aspx".  Instead, the code normally found in the code-behind file is defined within the .aspx file itself, using <script runat="server">.

    I wanted to separate out the data access code (since I will need the same calls for another page), and so created a "DataAccess.cs" file and placed it under the "App_Code" directory.  There is no namespace -- just a class, "DataAccess", with various methods defined to get data from the database.

    In VS2017, I have no problem seeing the class, and hooking into the methods via Intellisense.

    For deployment, I copied the "Report.aspx" file to the "...\LAYOUTS\ReportsApp" directory, and the "DataAccess.cs" file to the "...\LAYOUTS\ReportsApp\App_Code" directory on the server.

    When I run the report, I get "Error : the type or namespace name does not exist in the namespace (are you missing an assembly reference )".  I know that the code in "DataAccess.cs" is good, because if I put the code directly into the .aspx page, everything displays fine.

    I have variously searched the web.  One suggestion was to right-click on the "DataAccess.cs" file in VS2017, and choose "Compile".  That option is not listed when I right-click (maybe a WAP vs. WSP issue?), and when I look at the Properties (via F4), all I have is path names.

    I tried implementing a Namespace.  That did not help, including referencing it via <%@ Import Namespace="XXXXXXX" %> at the top of the Report.aspx" page (got error).

    I made a separate solution/project which included just the "DataAccess.cs" file, compiled it into a .dll, and put it in the "...\LAYOUTS\ReportsApp", ...\LAYOUTS\ReportsApp\App_Code" and ...\LAYOUTS\ReportsApp\Bin" directories without success -- although Intellisense was just fine with it after I did Add --> Reference.

    Finally, I tried modifying web.config:

    <configuration>
       <system.web>
          <compilation>
             <codeSubDirectories>
               <add directoryName="App_Code"/>
             </codeSubDirectories>
          </compilation>
       </system.web>
    </configuration>

    but I got the error: "System.Configuration.ConfigurationErrorsException: The element 'codeSubDirectories' cannot be defined below the application level."

    So, given my constraints (SharePoint 2013, .aspx file without code-behind), can one use a separate .cs code file from the .aspx page, and if so, what must one do to make it happen?

    P.S., one solution I did not try was putting the .dll in the GAC, but if that is the only solution, then I'll just include the data access code in "Report.aspx" -- it's simply not worth the hassle of dealing with admins to get something this trivial into the GAC.

     

    Thursday, September 5, 2019 4:21 AM

All replies

  • Please take a look at how to create Application pages in SharePoint. You can follow the links given below:

    https://docs.microsoft.com/en-us/visualstudio/sharepoint/creating-application-pages-for-sharepoint?view=vs-2019

    https://www.c-sharpcorner.com/article/steps-to-custom-application-pages-in-sharepoint-2013-using-visual-studio/

    Thanks,

    Harshal


    Please remember to mark the replies as answers if they helped. If you have feedback for TechNet Subscriber Support, contact tnmff@microsoft.com.

    Thursday, September 5, 2019 6:36 AM
  • Thanks for your reply.  The links pointed to resources that I found helpful in general and are much appreciated.

    I did try to create a simple, standard Test.aspx page with a Test.aspx.cs code-behind that ran within the following SharePoint context:

    <%@ Page Language="C#" DynamicMasterPageFile="~masterurl/custom.master" Inherits="Microsoft.SharePoint.WebControls.LayoutsPageBase" Trace="false" AutoEventWireup="true" CodeFile="Test.aspx.cs" %>

    but it errored out with:

    System.Web.HttpException: Error parsing attribute 'dynamicmasterpagefile': Type 'System.Web.UI.Page' does not have a public property named 'dynamicmasterpagefile'.  

    I transferred the code from the code-behind into the .aspx page, using a <script runat="server"> tag, and it ran fine.

    It may be that, while this is running in a SharePoint 2013 environment, the code I'm tasked with modifying is a throwback to the early 2000s (comments point to mid-2001), and thus operates off an earlier coding paradigm.  Is this possibly the case?  Because frankly, this is the first I've seen where the C# code is embedded in the .aspx page.  Thanks.
    Thursday, September 5, 2019 5:30 PM
  • Hi,

    Demo for Code separation.

    You need set page referenced assembly and inherit class.

    Create a library(PageCodeDll).

    Implement your page code behind, inherit proper class based on your page type.

    Get dll information by PowerShell.

    ([system.reflection.assembly]::loadfile("C:\Lee\SPProject\PageCodeDll\bin\Debug\PageCodeDll.dll")).FullName


    Update PageCodeSplit.aspx.

    <%@ Assembly Name="PageCodeDll, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5542d6f31983211e" %>
    <%@ Import Namespace="Microsoft.SharePoint.ApplicationPages" %>
    <%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
    <%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
    <%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
    <%@ Import Namespace="Microsoft.SharePoint" %>
    <%@ Assembly Name="Microsoft.Web.CommandUI, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
    <%@ Page Language="C#" AutoEventWireup="true" Inherits="SPProject.Layouts.SPProject.PageCodeSplit" DynamicMasterPageFile="~masterurl/default.master" %>
    
    <asp:Content ID="PageHead" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
    
    </asp:Content>
    
    <asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
        <asp:Button ID="btn_Test" OnClick="btn_Test_Click" runat="server" Text="Button" />
        <asp:Label ID="lb_Tip" runat="server" Text="Label"></asp:Label>
    </asp:Content>
    
    <asp:Content ID="PageTitle" ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">
    Application Page
    </asp:Content>
    
    <asp:Content ID="PageTitleInTitleArea" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server" >
    My Application Page
    </asp:Content>
    



    Best Regards,

    Lee


    Please remember to mark the replies as answers if they helped. If you have feedback for TechNet Subscriber Support, contact tnmff@microsoft.com.

    SharePoint Server 2019 has been released, you can click here to download it.
    Click here to learn new features. Visit the dedicated forum to share, explore and talk to experts about SharePoint Server 2019.

    Friday, September 6, 2019 2:29 AM
  • You can try "MasterPageFile" instead of DynamicMasterageFile" and see if the error disappears.

    OR

    You can remove "DynamicMasterPageFile" attribute from the markup and try adding this in code behind. It works the same but can call a bit of a hack.
    protected void Page_PreInit(object sender, EventArgs e)
        {
          // Override master page
          this.MasterPageFile = "../../_catalogs/masterpage/custom.master";
        } 

    Try it and let me know if it works 

    Please remember to mark the replies as answers if they helped. If you have feedback for TechNet Subscriber Support, contact tnmff@microsoft.com.


    • Edited by HarshalGite Friday, September 6, 2019 7:06 AM
    Friday, September 6, 2019 7:03 AM
  • Sorry for the tardy reply -- I was pulled off to address other issues ...

    HarshalGite, I tried both your suggested approaches, but could not get them to work. 

    Thinking that it might be a file reference issue, I did a broad file search on "custom.master", but it didn't turn up anything.  I talked with the head network guru, and he said that the custom.master might be "ghosted" by SharePoint.

    Wednesday, September 11, 2019 4:07 PM
  • Lee,  I tried your solution, but I think your solution has what I would call a more traditional approach to WebForms (i.e., a .csproj with a "references", etc.).  Unfortunately, this particular implementation is different.  Below is a screenshot (sorry for the size) showing the code from your post, along with the Solution Explorer.  You will note that the "<asp:" is an unrecognized code prefix, and the "using Microsoft.SharePoint.WebControls;" is also unrecognized (probably because there isn't a "References" for the solution/project).  If you know how I could convert this to a more traditional WebForms project, I can certainly give that a try.  Thanks.


    Wednesday, September 11, 2019 6:19 PM
  • Hi,

    I added custom.master as a reference. You can change it to the name of the master file you want to apply. If that doesn't work then try removing first "../" and then if still it does not work then try removing both ".." and start with "/_catalogs/". Try and update the code here.


    Please remember to mark the replies as answers if they helped. If you have feedback for TechNet Subscriber Support, contact tnmff@microsoft.com.

    Wednesday, September 11, 2019 6:59 PM
  • Hi HarshalGite,

    I tried adjusting the file path reference.  Unfortunately, no luck. One of the messages that I got was:

    System.Web.HttpException: The file '/_layouts/15/workload/_catalogs/masterpage/custom.master' does not exist.

    So, I did a file search on "_layouts" and "_catalogs".  Again, no luck, even after checking the entire "wwwroot" directory structure, as well as the entire actual path to the code:

    c:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\TEMPLATE\LAYOUTS\Report\Test.aspx

    BTW, I created a test.aspx page with a code-behind to limit the possibilities.  Here's the code (FYI: the second, commented out page directive is what I've been told to put at the top of the page ...):

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Test.aspx.cs" Inherits="Test" %>
    <%--<%@ Page Language="C#" DynamicMasterPageFile="~masterurl/custom.master" Inherits="Microsoft.SharePoint.WebControls.LayoutsPageBase" Trace="false" %>--%>
    
    <asp:content id="Main" contentplaceholderid="PlaceHolderMain" runat="server">
    
        <asp:Label ID="DisplayMainPageLabel" runat="server" Text="">
    
            <div>
                <asp:Button ID="Button1" Text="Button" OnClick="Button1_Click" runat="server" /> &nbsp; &nbsp;
                <asp:Literal ID="Literal1" runat="server">Literal #1</asp:Literal> &nbsp; &nbsp;
                <asp:Literal ID="Literal2" runat="server">Literal #2</asp:Literal> &nbsp; &nbsp;
            </div>
    
        </asp:Label>
        
        <%-- <script runat="server">
            protected void Page_Load(object src, EventArgs e)
            {
                if (Page.IsPostBack)
                {
                    Literal1.Text = "Page.IsPostBack";
                    return;
                }
                Literal1.Text = "Page_Load";
            }
            protected void Button1_Click(object sender, EventArgs e)
            {
                Literal2.Text = "Button Click";
            }
        </script>    --%>
    
    
    </asp:content>
    
    
    Here's the code-behind:
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    public partial class Test : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (Page.IsPostBack)
            {
                Literal1.Text = "Page.IsPostBack";
                return;
            }
            Literal1.Text = "Page_Load";
        }
    
        protected void Button1_Click(object sender, EventArgs e)
        {
            Literal2.Text = "Button Click";
        }
        
        protected void Page_PreInit(object sender, EventArgs e)
        {
            // Override master page
            this.MasterPageFile = "_catalogs/masterpage/custom.master";  //"~masterurl/custom.master";  // "../../_catalogs/masterpage/custom.master";
        }
    }
    

    Wednesday, September 11, 2019 9:44 PM
  • Hi ,

    My test demo is based on SharePoint project(as the page will host in SharePoint so it depends on SharePoint(authentication & authorization), it doesn’t make sense you host a pure asp.net page in SharePoint(although you could do this).


    Visual Studio need know the referenced library in project references.


    Best Regards,

    Lee


    Please remember to mark the replies as answers if they helped. If you have feedback for TechNet Subscriber Support, contact tnmff@microsoft.com.

    SharePoint Server 2019 has been released, you can click here to download it.
    Click here to learn new features. Visit the dedicated forum to share, explore and talk to experts about SharePoint Server 2019.

    Monday, September 16, 2019 8:13 AM