简体   繁体   中英

Extension method must be defined in a non-generic static class - Pulling XML from document

I'm currently writing up an upload system that takes XML from the document and will display it on a web page.

The issue I'm facing, is that whenever I'm adding the XML extraction part of the website, the compiler will return the error as mentioned in the title.

My code currently looks like this.

The part that is causing the problem is the publicstatic Xnamespace w and all the following relevant XML code. Cheers.

<script runat="server">
    //This template is being built to allow the viewstates to be displayed and allow them to be hidden
    //or shown at the same time. The buttons are being added so we can test whether they will
    //be hidden on page use


    public string _TempFileLocation = ""; //Used to locate Word Document File Path 


    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {


            string viewStateDisplay1 = "ViewState1 is now being displayed";
            string viewStateDisplay2 = "ViewState2 is now being displayed";
           // var ViewShow = viewStateDisplay1;
           // var ViewShow2 = viewStateDisplay2; 

            if (ViewState["PageState"] == null)
            {
                ViewState["PageState"] = viewStateDisplay1;
            }

                else
                {
                    ViewState["PageState"] = viewStateDisplay2;
                    //viewStateDisplay = false;
                }
        }

    }

    //button that shows the label string
    protected void btnClick_Click(object sender, EventArgs e)
    {
        lblString.Text = ViewState["PageState"].ToString();
        lblString.Visible = true;
    }

    //button that hides the div, changing "lblstring" or adding more should be able to hide 
    //or show whatever methods / objects we want
    private void Close(object sender, EventArgs e)
    {
        lblString.Visible = !lblString.Visible;
        lblString.Visible = false;
    }


    //This will be the default set for the page. It will start on true for viewstatedisplay
    //this will be done again, but with viewstatedisplay2 for the next method regarding 
    //the two columns and displaying document and DB data. "viewStateDisplay2.Visible = true"

    //private void gotoviewStateDisplay1(object sender, EventArgs e)
    // {
    //   ViewState("PageState") = 1;
    //   viewStateDisplay1.Visible = true;
    //   viewStateDisplay2.Visible = false;
    //}

    //private void gotoviewStateDisplay2(object sender, EventArgs e)
    // {
    //   ViewState("PageState") = 2;
    //   viewStateDisplay1.Visible = false;
    //   viewStateDisplay2.Visible = true;
    //}




    //THE USER UPLOAD CONTROL. users use this to upload the document to the server
    //This has validation so they cannot upload wrong file types / too large files

   // public partial class UploadFileControl : System.Web.UI.UserControl
  //  {

        //ViewState1 

        public void XMLextractor(string _filePath)
        {

            //XML extraction code
           displayFilepath.Text = _filePath;
           _TempFileLocation = _filePath;

        }

        //names the script manager which will be used when the user attempts to upload a form / gives an error if they incorrectly attempt to upload
        protected void UploadButton_Click(object sender, EventArgs e)
        {
            //if file is located
            if (FileUploadControl.HasFile)
            {
                try
                {
                    //allow content type of document / docx
                    if (FileUploadControl.PostedFile.ContentType == "application/vnd.openxmlformats-officedocument.wordprocessingml.document")
                    {
                        //if the file is is less than 51mb
                        if (FileUploadControl.PostedFile.ContentLength < 10485760) // 10mb)
                        {
                            //name the filename, find the path of the name
                            string filename = Path.GetFileName(FileUploadControl.FileName);
                            //path of server upload (we just need to save it as a variable to be found on the next page, as it will be made / deleted
                            FileUploadControl.SaveAs(Server.MapPath("~/") + filename);
                            //update the label with file uploaded
                            StatusLabel.Text = "Upload status: File uploaded!";

                            XMLextractor(Server.MapPath("~/") + filename);

                            //move onto template wizard page
                            //Response.Redirect("http://portal.acoura.com/admin/templatewizard.aspx", false);

                          WordprocessingDocument _TempDoc = WordprocessingDocument.Open(Server.MapPath("~/") + filename, true);

                         labelContentControls.Text = fileUpload_Displayx(GetContentControls(_TempDoc));

                            //will be used to grab the document string
                            //return;

                        }
                        else
                            //display the size the file needs to be less than
                            StatusLabel.Text = "Upload status: The file has to be less than 10mb!";
                    }
                    else
                        //tell the user only docx files are accepted
                        StatusLabel.Text = "Upload status: Only DOCX files are accepted!";
                }
                catch (Exception ex)
                {
                    //display the exception message, in which case it would be either size / type / if it's present
                    StatusLabel.Text = "Upload status: The file could not be uploaded. The following error occured: " + ex.Message;
                }


            }

        }
   // }

   //insert or link to XMLfromDocument file here. This will declare the variables
   //and take the required XML sections from the content controls of a document
   //needs to run as the file is uploaded, then return the control content titles

       // internal static class W
       //{

        //}


        public static XNamespace w =
            "http://schemas.openxmlformats.org/wordprocessingml/2006/main";

        public static XName body = w + "body";
        public static XName sdt = w + "sdt";
        public static XName sdtPr = w + "sdtPr";
        public static XName tag = w + "tag";
        public static XName val = w + "val";
        public static XName sdtContent = w + "sdtContent";
        public static XName tbl = w + "tbl";
        public static XName tr = w + "tr";
        public static XName tc = w + "tc";
        public static XName p = w + "p";
        public static XName r = w + "r";
        public static XName t = w + "t";
        public static XName rPr = w + "rPr";
        public static XName highlight = w + "highlight";
        public static XName pPr = w + "pPr";
        public static XName color = w + "color";
        public static XName sz = w + "sz";
        public static XName szCs = w + "szCs";


        public static XDocument GetXDocument(this OpenXmlPart part)
        {
            XDocument xdoc = part.Annotation<XDocument>();
            if (xdoc != null)
                return xdoc;
            using (Stream str = part.GetStream())
            using (StreamReader streamReader = new StreamReader(str))
            using (XmlReader xr = XmlReader.Create(streamReader))
                xdoc = XDocument.Load(xr);
            part.AddAnnotation(xdoc);
            return xdoc;
        }

        public static XElement GetContentControls(WordprocessingDocument document)
        {

            XElement contentControls = new XElement("ContentControls",
                document
                    .MainDocumentPart
                    .GetXDocument()
                    .Root
                    .Element(W.body)
                    .Elements(W.sdt)
                    .Select(tableContentControl =>
                        new XElement("Table",
                            new XAttribute("Name", (string)tableContentControl
                                .Element(W.sdtPr).Element(W.tag).Attribute(
                                    W.val)),
                            tableContentControl
                                    .Descendants(W.sdt)
                                    .Select(fieldContentControl =>
                                            new XElement("Field",
                                                new XAttribute("Name",
                                                    (string)fieldContentControl
                                                          .Element(W.sdtPr)
                                                          .Element(W.tag)
                                                          .Attribute(W.val)
                                                    )
                                            )
                                    )
                        )
                    )
            );
            //display the content controls in a web form in this project using this, the control will have to be added to templatewizard
            return contentControls;

            //need to mark the source which will be a file in the same directory as this for test purposes.

        }
   //display the TemplateWizard boxes and button here, hide viewstate and display viewstate2  
   //display content controls from doc on box1, field names from DB in box2
   //just create a string here that represents the final state of data being taken from XMLfromDocument


      // public string fileUpload_Displayx (XElement _contentcontrol)
      // {
      //      string str= "";
       //     str= _contentcontrol.Name.ToString();

       //    return str;

     //  }

   //public static displayDatabase(object sender, EventArgs e)
  // {

   //}
   //run the validate button on templatewizard, will mark up any problems or give green light


   //if red, allow users to replace fields in the left column, from ones in the atabase on the right


   //display upload button when validation is succesful. When Upload button runs, Take to new 
   // / existing page of reports, allow users to download this 






</script>

<!-- The following section will include all the html and forms etc !-->

<!-- on implementation, create different divs for each section, and style appropriately.  !-->
<div>


<!--Testing View state form!-->
ViewState Data: <b><asp:Label ID="lblString" runat="server"/></b>
<asp:Button ID="btnClick" runat="server" Text="Get ViewState Data" OnClick="btnClick_Click"/>
<asp:Button ID="Closeform" runat="server" Text ="Hide PageState" OnClick="Close" />


<br /><br /><br /><br /><br />

<!-- User upload control !-->
<asp:FileUpload id="FileUploadControl" runat="server" />
<asp:Button runat="server" id="UploadButton" text="Upload" onclick="UploadButton_Click" />
<asp:TextBox Text="" runat="server" ID="displayFilepath" />
<br /><br />
<asp:Label runat="server" id="StatusLabel" text="Upload status: " />

 <br /> <br /> <br /> <br />



<!-- Viewdata2, the document and data from DB will be displayed !-->

<!-- Document data !-->
<div id="box1" class="box">

    <div class="box-top">
        Data Sources inside document
    </div>
    <div class="box-middle">
        <asp:Label runat="server" id="labelContentControls" text="label of content in document" />
        <p> Test </p>
        <p> Test </p>
    </div>
    <div class="box-bottom">
    </div>
</div>    

<!--Data from DB !-->
<div id="box2" class="box">

    <div class="box-top">
        Data sources existing on the server
    </div>
    <div class="box-middle">
        <asp:Label runat="server" id="labelDatabasefields" text="label of content in database" />
        <p> Test </p>
        <p> Test </p>
    </div>
    <div class="box-bottom">
    </div>
</div>


<input type="button" value="Create Template" id="view" class="form_button"/>



</div>

Well yes, this is the problem:

public static XDocument GetXDocument(this OpenXmlPart part)

That's not being declared within a top-level static non-generic class, which extension methods have to be.

I would strongly advise you to stop mixing your code and HTML - put the code in code-behind and other classes. The GetXDocument method will need to be in a separate class, as it'll need to be in a static class as per the compilation error.

EDIT: One nasty alternative would be to just make it not an extension method:

public static XDocument GetXDocument(OpenXmlPart part)

then your call that looks like this:

document.MainDocumentPart
        .GetXDocument()

will need to be:

GetXDocument(document.MainDocumentPart)

C# allows to create extensions methods . Method with this keyword in definition, like your:

  public static XDocument GetXDocument(this OpenXmlPart part)

But this extension methods can be placed only in static class. You can't place them in non static class. So you need to move it to new static class and use it, or just remove this keyword and use as usual method

You have defined the extension method in wrong place. Define extension method GetXDocument in some static class instead of defining in Page class.

public static class YourStaticMethods
{
       public static XDocument GetXDocument(this OpenXmlPart part)
        {
            XDocument xdoc = part.Annotation<XDocument>();
            if (xdoc != null)
                return xdoc;
            using (Stream str = part.GetStream())
            using (StreamReader streamReader = new StreamReader(str))
            using (XmlReader xr = XmlReader.Create(streamReader))
                xdoc = XDocument.Load(xr);
            part.AddAnnotation(xdoc);
            return xdoc;
        }
}

Extension method example for adding method to string class.

namespace ExtensionMethods
{
    public static class MyExtensions
    {
        public static int WordCount(this String str)
        {
            return str.Split(new char[] { ' ', '.', '?' }, 
                             StringSplitOptions.RemoveEmptyEntries).Length;
        }
    }   
}

You can learn about Extension methods here .

This method :

    public static XDocument GetXDocument(this OpenXmlPart part)
    {
       ....
    }

has to be declared in public static class of your application. Like, for example:

public static class Extensions {


        public static XDocument GetXDocument(this OpenXmlPart part)
        {
          ....
        }
}

By writing this OpenXmlPart you specify an ExtensionMethod . This is another, "fancy" way, to implement Decorator pattern in .NET application.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM