Skip to content

Oracle AutoVue integration with web application as a drawing viewer

June 18, 2014

Oracle AutoVue (ver 20.2 in this example) has a Java applet which can be embedded in a web page. I was reluctant to include Java applets in my enterprise web applications because they depend on user’s local machine setting and can be broken by future Java updates (it has a notorious past history particularly with Smarteam). But Oracle AutoVue is almost the only possible option when you want to show CATIA based drawings in web pages.

Shop floor people have wanted to see a “rough look” of a part in intranet web applications because sometimes it’s difficult to differentiate parts just with part numbers, particularly when there are lots of left and right parts. We could add just simple photos of completed parts to the database but the Engineering department’s concern was how we can maintain the accuracy of the picture when design drawings are frequently changing.

For a long time, I didn’t have an answer for this concern. But now I realized if I embed the Oracle AutoVue in a web page and link to the Smarteam database in order to retrieve the latest drawings, I have a solution for this concern. Smarteam API has a functionality of composing a view file in cgr (“CATIA Graphical Representation”) format on-the-fly and copy it in a temporary folder. This means that not only we can show a drawing but also show it in 3-D form when the base drawing of a part is a 3-D file. Users can even turn it in their browsers. How cool is that?

Vision AutoVue

Here is the applet code of Oracle AutoVue embedded in an asp.net page:

    <!-- BEGIN AutoVue for Java Applet -->
    <APPLET NAME="JVue"

        CODE="com.cimmetry.jvue.JVue.class"
        CODEBASE="http://172.0.0.23/jVue"
        ARCHIVE="jvue.jar,jogl.jar,gluegen-rt.jar"

        HSPACE="0" VSPACE="0"
        WIDTH="100%" HEIGHT="100%" MAYSCRIPT>

        <PARAM NAME="EMBEDDED" VALUE="true">
        <PARAM NAME="VERBOSE"  VALUE="ERROR">

        <!-- Optional: To call a Javascript function after the applet has initialized -->
        <PARAM NAME="ONINIT"   VALUE="onAppletInit();">

	<!-- Optional: To call a Javascript function after the applet initialization fails -->
	<!-- <PARAM NAME="ONINITERROR" VALUE="onAppletInitError"> -->
    
        <!-- Set FILENAME parameter to the file you want to view at start            -->
        <PARAM NAME="FILENAME" VALUE='<%=FileURL%>' >
 
        <!-- Try direct socket connection  and  servlet tunnelling -->
        <PARAM NAME="JVUESERVER" VALUE="http://172.0.0.23:5098/servlet/VueServlet;">

        <p><b>Requires a browser that supports Java.</b></p>

    </APPLET>
    <!-- END AutoVue for Java Applet -->

You can set the public property FileURL from code behind. It can be web server’s local path or any URL. Since Java version 6, the enhanced security will display annoying error messages. You can avoid them by making a white list in Java control panel (this is a local settings). Make sure you include both Java applet server and web application server if they are from different machines.

Docx, xlsx, pptx files get corrupted when read back from database

June 17, 2014

You save an uploaded file of docx (or any MS Office file with trailing x, xlsx, pptx extension) into a SQL database. Then later try to open it from an ASP.NET page after retrieving from database, MS Word says “We’re sorry. We can’t open ….docx because we found a problem with its contents“. After click OK, it shows “Word found unreadable content in …..docx. Do you want to recover the contents of this document?”  

I spent several hours to debug this and tried all possible solutions suggested from others but no good. Then finally, I realized the problem may not be in the reading code but in the writing part. When I changed this part of writing a file into db :

Dim FILE_CONTENT(len) As Byte
File.InputStream.Read(FILE_CONTENT, 0, len)
SaveFileToDatabase(FILE_NAME, CONTENT_TYPE, FILE_CONTENT)

to :

Dim FILE_CONTENT(0 To len - 1) As Byte

then the reading error disappeared. I just forgot VB actually allocates N+1 elements from 0 to N when you dimension an array without specifying the lower bound. Hope that helps.

Smarteam API programming

May 28, 2014

In order to put the required DLLs into GAC, install Smarteam Editor client program in your dev machine (and web server later for deployment). In this example, I used version V5-6R2012 Service Pack 5. In Visual Studio 2012, create a new console project and add references.

SmarteamAPI References

    Sub Main()
        'Test input (DocumentID & ClassID) & etc.
        Dim ClassID As Integer = 949
        Dim ObjectID As Integer = 232216

        Dim myConfigName As String = "SmTeam32"
        Dim mySmarteamDbPwd As String = "DbPasswordEncrypted"
        Dim tempFolder As String = "C:\Temp"
        Dim StUsername As String = "myUserName"
        Dim StPassword As String = "MyPassword"
        Dim SmarteamEngine As SmApplic.SmEngine = Nothing
        Dim mySession As SmApplic.SmSession = Nothing

        Try
            'Create & init a Smarteam engine
            SmarteamEngine = New SmApplic.SmEngine
            SmarteamEngine.Init(myConfigName)
            SmarteamEngine.ServerMode = True 'Only when you use Smarteam API in a server environment

            'Create & init a Smarteam session
            mySession = New SmApplic.SmSession()
            mySession.Init(SmarteamEngine, "MyApplication", myConfigName)
            mySession.OpenDatabaseConnection(SmarteamEngine.Databases(0).Alias, _
                mySmarteamDbPwd, PasswordIsEncoded:=True)

            Dim IsSmarteamAuthenticated As Boolean = mySession.UserLogin(StUsername, StPassword)
            If Not IsSmarteamAuthenticated Then
                Throw New ApplicationException("Smarteam login failed.")
            End If

            Dim SmDefaultSessionUtil As SmUtil.SmSessionUtil = mySession.GetService("SmUtil.SmSessionUtil")
            Dim SmViewOperation As SmApplic.ISmOperation = mySession.MetaInfo.AllOperations(False).ItemByName("View")

            'Read a test object from the database
            Dim STDocument As SmApplic.ISmObject = mySession.ObjectStore.RetrieveObject(ClassID, ObjectID)
            If STDocument IsNot Nothing Then
                'Check permissions by Smarteam Security Model
                Dim IsAuthorized As Boolean = SmDefaultSessionUtil.OperationAllowedOnObjectAndAuthorized(STDocument, SmViewOperation, False)
                If Not IsAuthorized Then
                    Console.WriteLine("The document is not authorized to the current Smarteam login.")
                Else
                    Dim ViewFileName = SmDefaultSessionUtil.GetViewFileName(STDocument)
                    STDocument.CopyFileFromVaultPermission(ViewFileName, tempFolder, SmApplic.FileModeEnum.modReadOnly)
                    Dim ViewFilePath As String = tempFolder + "\" + ViewFileName
                    If System.IO.File.Exists(ViewFilePath) Then
                        Console.WriteLine("File '" + ViewFileName + "' sucessfully copied from the vault.")
                    End If
                End If
            End If

        Catch ex As Exception
            Console.WriteLine(ex.Message)
        Finally
            If mySession IsNot Nothing Then
                mySession.Close()
            End If
            If SmarteamEngine IsNot Nothing Then
                SmarteamEngine.Terminate()
            End If
        End Try

        Console.ReadKey()
    End Sub

The example is for a console application but I managed to put it on a web server for web application by creating the Engine and the Default Session in Global_asax.Application_Start().

From time to time, Smarteam API hanged up at session login. Our Smarteam administrator suggested to change the settings “Logger Enabled” from ‘true’ to ‘false’ in C:\Smarteam\bin\Logger.config file.  But the problem seems to be persistent. This sis not only a problem in API programming. Smarteam Desktop client too have similar hanging problem.

Reporting and Data Entering at the same time using Microsoft Reporting Service ReportViewer embedded in an ASP.NET page

April 12, 2013

5S

A Report is for displaying data not for editing. But what if you want to implement both functions using Microsoft SQL Server Reporting Service (SSRS) Report. In a standalone report web page from SSRS, it’s not possible unless you use report parameters for very simple data editing. But if an SSRS report is embedded in a ReportViewer of an ASP.NET page, you could use events that ReportViewer generates and mimicking data editing. I used BookmarkNavigation event.

1. Install SQL Server Data Tools – Business Intelligence if you haven’t yet. Once installed, you will find SQL Server Data Tools under SQL Server 2012 program group in start menu. ReportBuilder does not show all properties.

2. Edit Bookmark property of a report element (typically a textbox) you want to edit using SQL Server Data Tools. Since I needed three parameters to identify which score (o x in the screen shot) user clicked, I composed bookmark name something like “LTRIM(STR(Fields!ID_Audit.Value))+”:”+LTRIM(STR(Fields!ID_Item.Value))+”:2″ (example score=2). Also set the action property of the textbox to “Go to a Bookmark” as described in the capture below.

5s bookmark

3. In the code-behind file of ReportViewer host page, add the following event handler. You have to extract three parameters from the BookmarkNavigationEventArgs and update database.

4. After database updated, refresh the ReportViewer. There will be some flickering between postbacks. (Let them) Deal with it or try some UpdatePanel (I tried without success).

5. If you pop up a modal dialog extender panel for input inside the BookmarkNavigation event handler, you can edit text data fields(comment field in the screen shot, for example) too.

    Private Sub ReportViewer1_BookmarkNavigation(sender As Object, e As Microsoft.Reporting.WebForms.BookmarkNavigationEventArgs) Handles ReportViewer1.BookmarkNavigation
        e.Cancel = True 'We didn't want to navigate actually. We use this event just for communication between ReportViewer & WebServer        

        'This assumes the BookmarkId is a three-word string delimited by ":" (ID_Audit:ID_Item:Score)
        Dim tokens() As String = e.BookmarkId.Split(":")

        If tokens.Length >= 3 Then
            Dim ID_Audit As Integer = Val(tokens(0))
            Dim ID_Item As Integer = Val(tokens(1))
            Dim Score As Integer
            Int32.TryParse(tokens(2), Score)

            'Update database 
            ObjectDataSource_AuditDetail.UpdateParameters("ID_Audit").DefaultValue = ID_Audit
            ObjectDataSource_AuditDetail.UpdateParameters("ID_Item").DefaultValue = ID_Item
            ObjectDataSource_AuditDetail.UpdateParameters("Score").DefaultValue = Score
            ObjectDataSource_AuditDetail.Update()

            'After database is updated, refresh the ReportViewer
        End If
    End Sub

You might ask what’s the point of using SSRS report when you are already developing an ASP.NET web application which can have rich interface for data editing. Well, sometimes you need a very quick one page implementation of data reporting which also needs relatively simple data editing and the Report was already developed (in my case, by other system analyst). Then you may want to take advantage of it.

After completion of this project, I found a similar method described in this link, which was basically using hyperlink action instead of bookmarks. I tried the same method but it bothered me that I had to include web server’s URL in the hyperlinks (with parameters in query string) of the report element because I had to maintain two versions of reports for developing and deploying. Basically it creates one more dependency you have to take care of. Performance seemed to have a slight difference too. The bookmark method seemed just a little bit faster though I am not sure.

How to maintain scroll position of a gridview

April 12, 2013

There are two different approaches depending on whether the gridview is inside an UpdatePanel or not. If it’s not inside an UpdatePanel, then put javascript caller in div definition : “onscroll=SetDivPosition();”

    // Maintain Gridview scroll position. (Partial Postback (UpdatePanel) version)-----
    var yPos;
    var prm = Sys.WebForms.PageRequestManager.getInstance();

    function BeginRequestHandler(sender, args) {
        if ($get('<%= divGridview.ClientID%>') != null) {
            yPos = $get('<%= divGridview.ClientID%>').scrollTop;
        }
    }

    function EndRequestHandler(sender, args) {
        if ($get('<%= divGridview.ClientID%>') != null) {
            $get('<%= divGridview.ClientID%>').scrollTop = yPos;
        }
    }

    prm.add_beginRequest(BeginRequestHandler);
    prm.add_endRequest(EndRequestHandler);
 
    // Maintain Gridview scroll position. (Non-UpdatedPanel version)-----
    window.onload = function () {
        var strCook = document.cookie;
        if (strCook.indexOf("!~") != 0) {
            var intS = strCook.indexOf("!~");
            var intE = strCook.indexOf("~!");
            var strPos = strCook.substring(intS + 2, intE);
            var divGridView = document.getElementById("<%= divGridview.ClientID%>")

            if (divGridView != null) {
                //remembered scroll position might be out of range if the length of GridView was shortened
                if (strPos > divGridView.style.height * 0.92) strPos = divGridView.style.height * 0.92;
                divGridView.scrollTop = strPos;

            }
        }
    }
  
    function SetDivPosition() {
            var intY = document.getElementById("<%= divGridview.ClientID%>").scrollTop;
        //document.title = intY;    //it changes the title of IE tab/window (side effect. disabled.)
        document.cookie = "yPos=!~" + intY + "~!";
    } 

Error “Collection cannot be null. Parameter name: c” in ASP.NET 4.5 WebForm page

January 24, 2013

I was upgrading an ASP.NET 3.5 site to 4.5 and got this error: “Collection cannot be null. Parameter name: c“. It occurs just after page databinding and I couldn’t set any debug point in my code. On top of that Google search for this error didn’t give me much useful information.

I tried to narrow down by removing most databound controls (Griview, Formview, DetailsView) in aspx file and reviving one by one. I finally cornered a DetailsView as the culprit. The error is gone when I added  “AutogenerateRows=”False””  to the DetailsView.

I guess the default behaviour of ASP.NET 4.5 has been changed regarding DetailsView property though I am not sure why this suddenly became an issue when 3.5 site was just working fine.  Anyway, I hope this can help other developers.

Paint Log

March 25, 2012
tags: , ,

 

A manufacturing logging system for our painters.