Marcos Vainer Loeff

ASP.NET MVC 5 with PI AF SDK: Part 1 - Introduction

Blog Post created by Marcos Vainer Loeff Employee on Oct 28, 2014

I remember that some vCampus community members have requested an example of using PI AF SDK with ASP.NET MVC. Hence, I have written this blog post that I expect many of you would refer to when developing your future web applications.

What is ASP.NET MVC?

ASP.NET MVC was first introduced in 2009 by Microsoft offering a new approach for developing web application.  This technology takes advantage not only of the new MVC pattern but also of the ASP.NET platform and .NET Framework. ASP.NET MVC 4 can be used in Visual Studio 2010 and 2012 while ASP.NET MVC 5 can be used in Visual Studio 2012 and 2013.

Objectives

We are going to create a web application that will search for PI Points and display the snapshots from all PI Points found using PI AF SDK. If you prefer, you can download the Visual Studio solution here.

 

Note: since the topic is not small, we are going to talk about security on a future blog post.

Create a new project

Open Visual Studio and click on File -->  New Project… -->  Visual C# -->  Web -->  ASP.NET Web Application. Figure 1 shows the screenshot for creating new project.

 

1581.fig1.png

 

Figure 1 – Creating a new  ASP.NET MVC project in Visual Studio.

 

For the name of your solution, please write “PIAFSDK-WebApplication” and click on “OK”.

 

On the next window, select the Empty template adding the folders and core references for MVC and then click on “OK”. Figure 2 shows the screenshot for selecting the template. We have chosen the empty template instead of the MVC template because the last option not only comes with the MVC binaries but also with some Controllers, Views, Layouts and the ASP.NET Identity responsible for the authentication and authorization from your web site. As we are not going to use many of those default files, the Empty template seemed to be a better option for me.

 

5556.fig2.png

 

Figure 2 – Selecting the ASP.NET template.

 

 

 

 

Add the Bootstrap package

As I am not a web designer, I am going to use the bootstrap library in order not only to improve the design quality of my web application but also to make it responsive.

 

Open Packager Manager Console and type: Install-Package Bootstrap. Visual Studio will copy not only the bootstrap files to your project but also jQuery since it is a pre-requisite for bootstrap. It will also create a new folder called Scripts where all the JS file are supposed to be stored. Some CSS files related to bootstrap are copied to the Content folder.

 

0451.fig3.png

 

Figure 3 – Solution Explorer from Visual Studio.

Create the Home Controller

Right click on the Controllers folder and select  Add --> Controller…. Under the “Add Scaffold” window, please select the option “MVC 5 Controller – Empty”. Type the name “HomeController” on the “Add Controller” window and click on “OK”.

 

The HomeController is the default controller selected in case it is not defined on the uri. It is defined on the RouteConfig.cs file under App_Start folder.

Add Actions to the Controller and create the Views

Two actions are needed for our web application to work. The action is called “Request” while the second is called “Result”. By default, the HomeController has one Action called Index. Add the Request and Result actions as shown below:

 

  public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View("Query");
        }

        public ActionResult Query()
        {
            return View();
        }

        public ActionResult Result()
        {
            return View();
        }
    }

Note that we have changed the returned View from the Index action. Previously, it would have tried to return the file Index.cshtml (the same name from the action), which does not exist.  After the change, it retrieves the file Query.cshtml.

 

Create the Views for Request and Result. In order to do so, right click on Query() and choose “Add View…”. On the “Add View” window, make sure that “Create as partial view” and "Use a layout page:" options are unchecked and click on the Add button. Repeat this same procedure for Result.

 

Both View files were created under the Home folder under the Views folder.  For both views add a paragraph within the div in order to identify them. For example, the Query.cshtml should have the content below:

 

@{
    Layout = null;
}

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Query</title>
</head>
<body>
    <div>
        <p>This is the Query page.</p>
    </div>
</body>
</html>


 

Run your application. If you receive the error similar to Figure 3, you should go to References and select System.Web.Mvc. Under properties, change the Copy Local option from “False” to “True” and try again.

 

1586.fig4.png

 

Figure 4 – Initial compilation error.

 

Hopefully, it would work fine and you will be able to access the Query page (http://localhost:51670 or http://localhost:51670/Home/Query) and the Result page (http://localhost:51670/Home/Result). Remember to replace the port number to the correct one on your browser.

Add the PI AF SDK reference

Right click on reference -->  Add reference… and add the OSIsoft.AFSDK assembly version 4.0.0.0 to the project.

 

If you try to compile and run the web application, you are probably going to receive another error shown on Figure 5.

 

5355.fig5.png

 

Figure 5 – Error after adding OSIsoft.AFSDK reference.

 

This error occurs when you build as AnyCPU. Sometimes Visual Studio doesn’t know which version of PI SDK (32 or 64 bit) it should choose. If you still wants to build as AnyCPU, there are two workarounds:

 

1.  In your post-build event command line settings for your project, delete the PI SDK assemblies which the build is copying into your bin directory

 

del "$(TargetDir)osisoft.pisdk.dll"

 

del "$(TargetDir)osisoft.pisdkcommon.dll"

 

del "$(TargetDir)osisoft.pitimeserver.dll"OR

 

2.  Add the 3 assemblies above from Program Files\PIPC\PISDK\PublicAssemblies to you project, and make sure the Copy Local setting is set to false.

 

I have chosen the first option, resulting on Figure 6.

 

2783.fig6.png

 

Figure 6 – Post-build event settings on Visual Studio.

 

If you try to recompile, hopefully you won’t receive any errors.

Create a new Model

On the solution explorer, right click on the Models folder and select -->  Add class. Name this class PIPointSnapshotModelView and click on OK. The content of this class should be:

 

public class PIPointSnapshotModelView
    {
        public string PIPointName { get; set; }
        public object Value { get; set; }
        public DateTime TimeStamp { get; set; }

        public PIPointSnapshotModelView(string piPointName, AFValue snapshot)
        {
            PIPointName = piPointName;
            Value = snapshot.Value;
            TimeStamp = snapshot.Timestamp;
        }
    }

The model is sent from the controller to be displayed on the View. We have chosen these properties since we want to display the snapshot value and its timestamp from all the PI Points found.

Change the Query View

Let’s edit the Query.cshtml which is the View associated to the Query action using the content below:

 

@{
    Layout = null;
}

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <link href="~/Content/bootstrap.css" rel="stylesheet" />
    <link href="~/Content/bootstrap-theme.css" rel="stylesheet" />
    <script src="~/Scripts/jquery-1.9.0.js"></script>
    <script src="~/Scripts/bootstrap.js"></script>
    <title>Query PI Data Archive</title>
</head>
<body>
    <div class="col-sm-8 col-sm-offset-2">
        <h1>My first ASP.NET MVC with PI AF SDK</h1>
        <br /><br />
        <h4>Search for PI Points and check its snapshots.</h4>
        <br /><br />
        <div class="container">
            <div class="row">
                @using (Html.BeginForm("Result", "Home", FormMethod.Get, new { @class = "form-inline", role = "form" }))
                {
                    <div class="form-group">
                        <label class="sr-only" for="name">Search PI Point: </label>
                        @Html.TextBox("piPointNameQuery", string.Empty, new { @class = "form-control", placeholder = "PI Point" })
                    </div>
                    <div class="form-group">
                        <label class="sr-only" for="inputfile">With this Point Source: </label>
                        @Html.TextBox("pointSourceNameQuery", string.Empty, new { @class = "form-control", placeholder = "Point Source" })
                    </div>
                    <button type="submit" class="btn btn-default">Submit</button>
                }
            </div>
        </div>
  </div>
</body>
</html>



Some comments about the above code snippet:

  1. Layout = null means that no Master page should be used for this page.
  2. Html.BeginForm is used to define the form which will send the query parameters to the Result action method.
  3. The query parameters are piPointNameQuery and pointSourceNameQuery. They will be sent to the Result action name.

Change the Query and Result actions

We have changed the Result Action in order to find the PI Points restricted by pointSourceNameQuery and piPointNameQuery input variables. This is achieved by using the PIPointQuery class from the OSIsoft.AF.PI namespace as well as the PIPoint.FindPIPoints method. A PIPointList object called pointlist stores the found PI Points. Finally, this object is converted to List<PIPointSnapshotModelView> which is sent to the View. Remember to change PISERVERNAME to the hostname of your PI Data Archive.

 

    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View("Query");
        }


        public ActionResult Query()
        {
            return View();
        }

        public ActionResult Result(string piPointNameQuery, string pointSourceNameQuery)
        {
            PIServer myPIServer = new PIServers()["PISERVERNAME"];
            PIPointQuery query1 = new PIPointQuery(PICommonPointAttributes.Tag, OSIsoft.AF.Search.AFSearchOperator.Equal, piPointNameQuery);
            PIPointQuery query2 = new PIPointQuery(PICommonPointAttributes.PointSource, OSIsoft.AF.Search.AFSearchOperator.Equal, pointSourceNameQuery);
            IEnumerable<PIPoint> foundPoints = PIPoint.FindPIPoints(myPIServer, new PIPointQuery[] { query1, query2 });
            PIPointList pointlist = new PIPointList(foundPoints.Take(1000));

            List<PIPointSnapshotModelView> PIPointSnapshotValueList = new List<PIPointSnapshotModelView>();
            foreach (PIPoint pipoint in pointlist)
            {
                PIPointSnapshotValueList.Add(new PIPointSnapshotModelView(pipoint.Name.ToString(), pipoint.Snapshot()));
            }
            return View(PIPointSnapshotValueList);
        }
    }



Change the Result View

The View will display on a table the information stored on the List<PIPointSnapshotModelView> . We have used some bootstrap syntax such as col-sm-8 which is used to define the width of the table.

 

@model List<PIAFSDK_WebApplication.Models.PIPointSnapshotModelView>
@{
    Layout = null;
}

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Results</title>
    <link href="~/Content/bootstrap.css" rel="stylesheet" />
    <link href="~/Content/bootstrap-theme.css" rel="stylesheet" />
    <script src="~/Scripts/jquery-1.9.0.js"></script>
    <script src="~/Scripts/bootstrap.js"></script>
</head>
<body>
    <div class="col-sm-8 col-sm-offset-2">
        <h1>My first ASP.NET MVC with PI AF SDK</h1>
        <br /><br />
        <table class="table">
            <tr>
                <th>PI Point</th>
                <th>Value</th>
                <th>Timestamp</th>
            </tr>
            @foreach (var piPointSnapshotValue in Model)
            {
                <tr>
                    <td>@piPointSnapshotValue.PIPointName</td>
                    <td>@piPointSnapshotValue.Value.ToString()</td>
                    <td>@piPointSnapshotValue.TimeStamp.ToString()</td>
                </tr>
            }
        </table>
        <br />
        <center>
            @Html.ActionLink("Make another search", "Index", "Home", new { @class = "btn btn-primary" })
        </center>
    </div>
</body>
</html>

We have added a button on the end of the page which will go back to the Query page so that the end-user can make another search with different parameters.

Testing the web application

We have finished writing our ASP.NET MVC web application. It is time to test. When you run this web application on Visual Studio, you should see the Query page below.

 

5722.fig7.png

 

Figure 7 – Screenshot of the Query page from our web application

 

Figure 10 shows a screenshot in case we want to find all PI Points which start with “sin” from any PI Point Source. After clicking on submit, it will show the table with the PI Points found on the Result page.

 

8664.fig8.png

 

Figure 8 – Screenshot of the Result page from our web application

 

Note that the design of the page has improved using bootstrap adding only a few words to the View. The query string defines the input parameters so you can edit them directly on the uri. If you click on “Make another search” it should go back to the previous page.

Conclusion

I hope you find this example interesting and you can refer to it when developing your next web applications with PI AF SDK. On the next blog post, I will test the new ASP.NET vNext with PI AF SDK using Visual Studio 14 CTP3.

Outcomes