Debug AVFP ver.6.03 with WS 2012

Topics: Developer Forum
Developer
Oct 31, 2013 at 3:08 AM
I don't think we got the debugger working in Ver 6.03(?).

If not, then this may be of interest.

I am was able to hook into VFP application object, when running AVFP under Visual Studio 2012. This gives 'set step' ability of VFP, from anywhere in the AVFP Project and also from any avfp pages.

But it is rudimentary and needs more development time. i.e.
1) fixing permission settings for VFP.. for doing ajax 'POST' ( I think..??),
2) has FoxPro environment settings ( I.e. set('xx')) of locally installed VFP IDE and not that to IIS server OLE session ( I think ..??),
3) gives VFP warnings on oResponse.Redirects() (...about current thread aborting.. WTF??),
4) etc etc...& etc.

Thing is, I already have developed a debugger more suitable for my customized version of AVFP and I do not want to spend any time on this new debugger (which is more suitable in CodePlex AVFP version).

If anyone wants to get my notes and work on it, I'll be happy to assist.
Coordinator
Oct 31, 2013 at 3:37 PM
It's listed in the items to fix but only has gotten 2 votes:

http://activevfp.codeplex.com/workitem/34439

The first page works in 6.03 just like 5.53 debugging. It's all the subsequent pages that aren't being debugged properly. There's probably a decent workaround that's not too difficult to implement.
Developer
Oct 31, 2013 at 6:02 PM
Edited Nov 9, 2013 at 2:14 PM
Yep, I cannot understand the reason for low votes. I would think, the ability to debug can make or break project timelines. The procedure to start debugging is the same as listed in documentation for 5.53. And I seem to I have reached much further then the first page. However, I am unable to make ajax POST calls (i.e. error 405 - method not allowed) using VFP proxy server and unless that works, it not something I can offer in codeplex. Other then this, I know the reasons that are creating the problems, so they should be easier to solve. I'll dump my notes here, so that it can be use as a reference for anyone attempting it in future. 1) AVFPHandler should tie down the least number of web resources. Ignoring security issues for the moment, we first need to remove all web.config files from subfolders ( css, image, etc). Change the root web config file as follows: ( note the change for REST handler for extension less calls) ``` <?xml version="1.0" encoding="UTF-8"?> <configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0"> <system.web> <httpModules> <clear /> <add name="HttpModule_ProcessManifest" type="MazeComputer.AspManifestHelpers.HttpModule_ProcessManifest, AspManifestHelpers" /> <add name="Session" type="System.Web.SessionState.SessionStateModule" /> </httpModules> <compilation debug="true" /> <httpHandlers> <add verb="*" path="*.avfp" type="AVFPHandler" /> <add verb="*" path="*.css" type="System.Web.StaticFileHandler" validate="false" /> <add verb="*" path="*.bmp" type="System.Web.StaticFileHandler" validate="false" /> <add verb="*" path="*.gif" type="System.Web.StaticFileHandler" validate="false" /> <add verb="*" path="*.png" type="System.Web.StaticFileHandler" validate="false" /> <add verb="*" path="*.ico" type="System.Web.StaticFileHandler" validate="false" /> <add verb="*" path="*.js" type="System.Web.StaticFileHandler" validate="false" /> <add verb="*" path="*.pdf" type="System.Web.StaticFileHandler" validate="false" /> <add verb="*" path="*" type="AVFPHandler" /> </httpHandlers> </system.web> <system.webServer> <modules> <add name="HttpModule_ProcessManifest" type="MazeComputer.AspManifestHelpers.HttpModule_ProcessManifest, AspManifestHelpers" preCondition="managedHandler" /> </modules> <validation validateIntegratedModeConfiguration="false" /> <defaultDocument> <files> <clear/> <add value="default.avfp"/> </files> </defaultDocument> <handlers> <add verb="*" path="*.avfp" name="AVFPHandler" type="AVFPHandler" /> <add verb="*" path="*." name="AVFPRESTHandler" type="AVFPHandler" /> </handlers> </system.webServer> </configuration> ``` 2) Changes in Proxystub.prg ``` FUNCTION Debugger() LOCAL loFox, lcReturn lcReturn = "" loFox = GETOBJECT(,"visualfoxpro.application.9") loFox.SetVar("oRequest",THIS.oRequest) loFox.SetVar("oSession",THIS.oSession) loFox.SetVar("oResponse",THIS.oResponse) loFox.SetVar("oServer",THIS.oServer) loFox.SetVar("oApplication",THIS.oApplication) loFox.DoCmd("SET RESOURCE OFF") loFox.DoCmd("SET EXCLUSIVE OFF") loFox.DoCmd("SET CPDIALOG OFF") loFox.DoCmd("SET DELETED ON") loFox.DoCmd("SET EXACT OFF") loFox.DoCmd("SET SAFETY OFF") loFox.DoCmd("SET REPROCESS TO 2 SECONDS") lcReturn = loFox.eval("proxystub()") RELEASE loFox RETURN lcReturn ENDFUNC ``` 3) Change in Proxstub ( replace all the code between the beginning of the file ...and.... 'DEFINE CLASS server AS ActiveVFP OLEPUBLIC' as follows.. ``` #DEFINE crlf CHR(13)+CHR(10) SET STEP ON oProp=NEWOBJECT('AVFPproperties','activevfp.prg') && create properties shared among classes oHTML=NEWOBJECT('AVFPhtml','activevfp.prg') oCookie=NEWOBJECT('AVFPcookie','activevfp.prg') oProp.ScriptPath=oRequest.servervariables("SCRIPT_NAME") oProp.SessID=NVL(oRequest.querystring("sid"),"") oProp.AppStartPath=JUSTPATH(oRequest.ServerVariables("PATH_TRANSLATED"))+[\] &&JUSTPATH(APPLICATION.SERVERNAME)+"\" oProp.AppName=STREXTRACT(oRequest.ServerVariables("PATH_INFO"),[/],[/]) &&blank if installed to root &&JUSTSTEM(APPLICATION.SERVERNAME) oProp.RunningPrg=[main.prg] ************************************************************** * REST-like APIs implementation * * Author: Victor Espina * Date: April 2012 * ************************************************************** * Create an instancia of RESTHelper class LOCAL oRESTHelper, cRootPath cRootPath = oRequest.serverVariables("APPL_PHYSICAL_PATH") oRESTHelper = NEWOBJECT("restHelper","PRG\RESTHelper.PRG") oRESTHelper.setFolder("ROOT", cRootPath) oRESTHelper.setFolder("CONTROLLERS", ADDBS(cRootPath) + "prg/rest/controllers") oRESTHelper.loadControllers() * Use RESTHelper object to check if the request conforms a REST-like API call. If so, pass * the request object to RESTHelper in order to let the right resource controller handle it. IF oRESTHelper.isREST(oRequest) oProp.appStartPath = oRequest.serverVariables("APPL_PHYSICAL_PATH") RETURN oRESTHelper.handleRequest(oRequest, oProp) ENDIF * If the request was not a REST-like API call, check if MAIN.PRG exists in * oProp.appStartPath. If it doesn't, we change oProp.appStartPath to point * to app's root folder. This will avoid an innecessary "file not found" * error. IF NOT FILE(oProp.appStartPath + "\PRG\MAIN.PRG") oProp.appStartPath = oRequest.serverVariables("APPL_PHYSICAL_PATH") ENDIF * If for some reason we can't find a valid processor, return * an error message IF NOT FILE(oProp.AppStartPath+'\prg\main.prg') RETURN "oRESTHelper: cannot find " + oProp.appStartPath+"\prg\main.prg" ENDIF ************************************************************** lcScript=FILETOSTR(oProp.AppStartPath+'\prg\main.prg') lcHTMLout= EXECSCRIPT(lcScript) &&main() && run the application RETURN lcHTMLout ``` 4) Add the following just below the line 'FUNCTION Process' in the proxystub.prg. Note that this is __only for debugging__. you must comment out the entire portion in production. Also this may be the cause of thread aborting message. Better manner may be to make change in the dll itself (and I don't know how to do that). In __fact if you start avfp, and if the following code has 'not' been commented out, then you will always get Run time__ error. To __avoid this error, open VFP (as administrator) before running AVFP__ in the manner documented for debugging V5.x In fact I have this portion running based on an <appSettings> value in Web.Config. ``` *-------+IMP:: Delete this in Production... Local loFox loFox = GETOBJECT(,"visualfoxpro.application.9") If VARTYPE(loFox) = "O" loFox = null Release loFox oProp=NEWOBJECT('AVFPproperties') Return this.Debugger() Endif Release loFox *-------+ Imp:: Delete this in Production... ``` 5) Change the main.prg. Replace the 'otherwise' portion of the Case .. endcase as follows. ``` OTHERWISE && get .avfp script *------+ Activate the debug thru VS 2012 Do Case case LOWER(oProp.Action) == "default" and LOWER(oProp.Ext) == ".aspx" oProp.Action = "default" oProp.Ext = ".avfp" lcHTMLout= FILETOSTR(oProp.HtmlPath+oProp.Action+oProp.Ext) oProp.RunningPrg=oProp.Action+oProp.Ext lcHTMLout= oHTML.mergescript(lcHTMLout) case !ISNULL(oProp.Action) .AND. FILE(oProp.HtmlPath+oProp.Action+oProp.Ext) * This section must stay here for pure scripting mode lcHTMLout= FILETOSTR(oProp.HtmlPath+oProp.Action+oProp.Ext) oProp.RunningPrg=oProp.Action+oProp.Ext lcHTMLout= oHTML.mergescript(lcHTMLout) Otherwise && goto default page * USE mydbf && test error CookieLogin() && checks for cookie to authenticate lcHTMLfile = 'default'+oProp.Ext If !FILE(oProp.HtmlPath+lcHTMLfile) *----+ Oct 2013.. default document is not being served by IIS.. force it. Local lcPath lcPath = ALLTRIM(oRequest.ServerVariables("SCRIPT_NAME")) lcPath = lcPath + IIF(RIGHT(lcPath,1) != '/','/','') oResponse.Redirect(lcPath+'default.avfp') endif lcHTMLout= FILETOSTR(oProp.HtmlPath+lcHTMLfile) oProp.RunningPrg=[default]+oProp.Ext lcHTMLout= oHTML.mergescript(lcHTMLout) Endcase ENDCASE ``` 6) To debug.. Follow the normal manner to open VS & VFP. However, you will need to use Default.aspx to start debugging. Debug properties for VS Start Options -> Start action -> Use current page Start Options -> server -> Use default web server Start Options -> debugger -> asp.net. Build -> start action -> benefire running startup page: -> Nobuild Build-> target framework 4.5 -> .net framework 4.5 Is IIS manager, Application pool -> <select the application pool used by your application> ->Basic Settings-> set .net framework to 4.0 and pipeline to integrated. 7) I hope I have included all the changes.. If you get it working for Ajax, please share. Good luck.
Coordinator
Oct 31, 2013 at 8:40 PM
Thanks. I'll try it. If we can SET STEP ON in the VFP debugger and step thru the VFP code on pages other than the first one with your techniques, that in itself would be a huge improvement for 6.03.
Developer
Nov 4, 2013 at 5:00 AM
Edited Nov 9, 2013 at 2:06 PM
Final update.... hopefully, we should now be able to have full 'set step' ability in V 6.03 also.

I've made debugging work when the web site's 'application pool' is on .net ver 2, in integrated mode. I think, this would be least disruptive to existing installs.
Update: .net ver 2 causes htmlencoding holes. I have application pool back on .net ver 4 in integrated mode.


I've already updated the changes required in the web.config file (in my previous comments). Note that we are now calling the images as static files in httpHandlers. If I missed any static file extension, then, it will need to be added in this section.

Also note that I have used both httphandlers ( which are related to .Net ver 2) and also handlers ( which are related to .net ver 3 or 4). This is done to handle Ajax calls.

Note that we have noticeable differences in IIS and .net development server. I did not try IIS Express.

Apart from deleting all web.config files ( except the web.config file in the application root), you can ( if you want to ), now revert these sub-directories to their 'non-application' states in IIS. To do this, go to the virtual 'sub' directory in IIS manager window, and do a right click, then click 'remove' in the context menu that comes up.
Developer
Nov 6, 2013 at 12:20 PM
Hi claudefox,

what does the following, in web.config, do?
    <add name="HttpModule_ProcessManifest" type="MazeComputer.AspManifestHelpers.HttpModule_ProcessManifest, AspManifestHelpers" />
It seems that I was unable to use Application pool using .net framework 4 (i.e. ajax was not working in debug mode). Suddenly, now it all seems to work. The only thing that I changed was to remove these MazeCoputer lines from web.config. Interestingly, it works now even after I restore these lines back into web.config. It could be, but I doubt it's to do with anything else... hence this question.

BTW, I did not delete the assembly from bin, just changed web.config.
Coordinator
Nov 6, 2013 at 2:12 PM
Edited Nov 6, 2013 at 2:17 PM
That's the side by side COM registration stuff. If you take that out you have to register the VFP server manually. And if you register the VFP server manually, you are basically limited to one ActiveVFP backend server per machine. IOW, all copies of your web apps in different folders will be using the one registered ActiveVFP instead of their own copy. Not good in my opinion.

If you register manually and have more than one folder/web application, it may work but you probably will start running into "file not found" errors and just general confusion since you may delete one folder with the registered ActiveVFP and then nothing will work. Again not good.

The best course is just to use the built-in side by side COM registration. It should always work automagically, but, if it doesn't, you should try to find out why it doesn't work and make it work instead of manually registering activevfp.dll, imo.
Developer
Nov 7, 2013 at 2:06 PM
Thanks. It'll make sense to keep it.

What I've not been able to figure out is even when I have application pool in IIS set to using .net framework 4.0 in integrated mode, AVFP seems to be behaving like it is set to using .net framework 4.0 in classic mode ( i.e. see the Web.config above).

Could it be because these dlls in bin folder are created in .net ver 2.0? If you can give me pointers on how to recreate these dlls in VS 2012 I'll be able to test them out.
Developer
Nov 9, 2013 at 2:38 PM
Waaaa...

I updated my comments dated Oct 31 above and now those comments lost all it's formatting. If anyone has an email of the original code, could they fix it from that email?

The change I was making to those comments, related to, 1) using the application pool set to .net framework 4.0 in integrated mode and 2) running the VS in no-build mode using .net framework 4.X

Also ensure that you have loaded the symbols. If S does not start debugger, then you can force VS to reload by flipping the .net framework ( point 2 above) to something else and putting it back to original value after re-opening VS.

Thanks
Coordinator
Feb 8 at 2:30 PM
This is very important. Can you detail the steps for debugging avfp603 exactly as you have done them?

And what do you mean by "hook into VFP application object, when running AVFP under Visual Studio 2012" ?? Do you mean attach process??

thanks!!
Developer
May 25 at 2:47 PM
Hey Claudefox.
Its been some time since I logged on to codeplex and have not spent time on AVFP for some time now. Is this still an issue?

My copy of AVFP ended up very different from original... but ill try to help as much as I can. Let me know.
Coordinator
May 27 at 8:14 PM
Yes! If you could please document how you accomplished debugging in avfp603 using VS, that would be tremendously helpful.

thank you.
Developer
May 28 at 4:20 PM
I am sending this in multiple msgs due to number of characters limilations in codeplex.

PAGE 1.

I'll try to cleanup my previous email which lists the changes required in AVFP demo project with some summary info. My development system was VFP ver 9, SQL server 2012, Visual Studio web developer 2012. The debug/development Web site was local to my machine.

a. Set step will fail on hitting the EXECSCRIPT() ( i.e. &). we replace these command by creating a physical file (prg) on disk, and running it, wherever possible, to get complete trace. However, EXECSCRIPT() still works but without tracing ability if the set step command is in the higher call stack.

b. In VS 2012, I start the debug after opening the default.aspx.


1) AVFPHandler should tie down the least number of web resources. Ignoring security issues for the moment, we first need to remove all web.config files from subfolders ( css, image, etc). Change the root web config file as follows: ( note the change for REST handler for extension less calls)
<?xml version="1.0"?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
  <system.web>
    <httpModules>
      <clear/>
      <add name="HttpModule_ProcessManifest" type="MazeComputer.AspManifestHelpers.HttpModule_ProcessManifest, AspManifestHelpers"/>
      <add name="Session" type="System.Web.SessionState.SessionStateModule"/>
    </httpModules>
    <!-- 
     Set compilation debug="true" to insert debugging 
     symbols into the compiled page. Because this 
     affects performance, set this value to true only 
     during development.
    -->
    <compilation debug="true" targetFramework="4.0"/>
    <!--
     The <authentication> section enables configuration 
     of the security authentication mode used by 
     ASP.NET to identify an incoming user. 
    -->
    <authentication mode="Windows"/>
    <httpHandlers>
      <add verb="*" path="*.avfp" type="AVFPHandler"/>
      <add verb="*" path="*.css" type="System.Web.StaticFileHandler" validate="false"/>
      <add verb="*" path="*.bmp" type="System.Web.StaticFileHandler" validate="false"/>
      <add verb="*" path="*.gif" type="System.Web.StaticFileHandler" validate="false"/>
      <add verb="*" path="*.png" type="System.Web.StaticFileHandler" validate="false"/>
      <add verb="*" path="*.ico" type="System.Web.StaticFileHandler" validate="false"/>
      <add verb="*" path="*.js" type="System.Web.StaticFileHandler" validate="false"/>
      <add verb="*" path="*.pdf" type="System.Web.StaticFileHandler" validate="false"/>
      <add verb="*" path="*" type="AVFPHandler"/>
    </httpHandlers>
    <!--
        The <customErrors> section enables configuration 
        of what to do if/when an unhandled error occurs 
        during the execution of a request. Specifically, 
        it enables developers to configure html error pages 
        to be displayed in place of a error stack trace.

    <customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
        <error statusCode="403" redirect="NoAccess.htm"/>
        <error statusCode="404" redirect="FileNotFound.htm"/>
    </customErrors>
  -->
    <pages controlRenderingCompatibilityVersion="4.0"/>
  </system.web>
  <system.webServer>
    <modules>
      <add name="HttpModule_ProcessManifest" type="MazeComputer.AspManifestHelpers.HttpModule_ProcessManifest, AspManifestHelpers" preCondition="managedHandler"/>
    </modules>
    <validation validateIntegratedModeConfiguration="false"/>
    <defaultDocument>
      <files>
        <clear/>
        <add value="default.avfp"/>
      </files>
    </defaultDocument>
    <handlers>
      <add verb="*" path="*.avfp" name="AVFPHandler" type="AVFPHandler"/>
      <add verb="*" path="*." name="AVFPRESTHandler" type="AVFPHandler"/>
    </handlers>
    <!-- The all VFP file Extensions  i.e. .prg .fxp etc need to be disabled from being called from browser 
         The following will work in non-debug mode only.
   Do the same with the directories using hiddenSegment tags   

   Also, to force the ajax calls to work.. we are setting the Access-Control-allow-origin setting to least security level
      -->
    <security>
      <requestFiltering>
        <fileExtensions>
          <add fileExtension=".prg" allowed="false"/>
          <add fileExtension=".fxp" allowed="false"/>
          <add fileExtension=".bak" allowed="false"/>
          <add fileExtension=".app" allowed="false"/>
          <add fileExtension=".cdx" allowed="false"/>
          <add fileExtension=".dbc" allowed="false"/>
          <add fileExtension=".dbf" allowed="false"/>
          <add fileExtension=".dll" allowed="false"/>
          <add fileExtension=".ocx" allowed="false"/>
          <add fileExtension=".pjt" allowed="false"/>
          <add fileExtension=".pjx" allowed="false"/>
          <add fileExtension=".tbk" allowed="false"/>
          <add fileExtension=".vct" allowed="false"/>
          <add fileExtension=".vcx" allowed="false"/>
          <add fileExtension=".dcx" allowed="false"/>
          <add fileExtension=".err" allowed="false"/>
          <add fileExtension=".exe" allowed="false"/>
          <add fileExtension=".fky" allowed="false"/>
          <add fileExtension=".fll" allowed="false"/>
          <add fileExtension=".fmt" allowed="false"/>
          <add fileExtension=".fpt" allowed="false"/>
          <add fileExtension=".frx" allowed="false"/>
          <add fileExtension=".idx" allowed="false"/>
          <add fileExtension=".dct" allowed="false"/>
          <add fileExtension=".txt" allowed="false"/>
        </fileExtensions>
        <hiddenSegments>
          <add segment="documentation"/>
          <add segment="Backups"/>
          <add segment="data"/>
          <add segment="debugger"/>
          <add segment="reports"/>
          <add segment="sysFiles"/>
        </hiddenSegments>
      </requestFiltering>
    </security>
    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*"/>
      </customHeaders>
    </httpProtocol>
  </system.webServer>
  <appSettings>
    <add key="Debugger" value="ON"/>
    <add key="Development" value="ON"/>
    <add key="ASPDebugger" value="ON"/>
  </appSettings>
</configuration>
2) Changes in Proxystub.prg.

Replace the debugger() method of server class as follows.
*************************************************************
* server :: debugger
* Last Modified: 12/30/11
* ActiveVFP Version 5.61
*************************************************************
FUNCTION Debugger()
LOCAL loFox, lcReturn
lcReturn = ""

loFox = GETOBJECT(,"visualfoxpro.application.9")


loFox.SetVar("oRequest",THIS.oRequest)
loFox.SetVar("oSession",THIS.oSession)
loFox.SetVar("oResponse",THIS.oResponse)
loFox.SetVar("oServer",THIS.oServer)
loFox.SetVar("oApplication",THIS.oApplication)

*-----+ Start WE need these for this VFP automation server
loFox.DoCmd("SET RESOURCE OFF")
loFox.DoCmd("SET EXCLUSIVE OFF")
loFox.DoCmd("SET CPDIALOG OFF")
loFox.DoCmd("SET DELETED ON")
loFox.DoCmd("SET EXACT OFF")
loFox.DoCmd("SET SAFETY OFF")
loFox.DoCmd("SET REPROCESS TO 2 SECONDS")
*-----+ Start WE need these for this VFP automation server

lcReturn = loFox.eval("proxystub()")

RELEASE loFox
RETURN lcReturn
ENDFUNC
Developer
May 28 at 4:27 PM
PAGE 2.

3) Change in Proxstub.prg ( replace all the code between the beginning of the file

...and....

'DEFINE CLASS server AS ActiveVFP OLEPUBLIC' as follows...
#DEFINE crlf CHR(13)+CHR(10)
SET STEP ON
oProp=NEWOBJECT('AVFPproperties','activevfp.prg')  && create properties shared among classes
oHTML=NEWOBJECT('AVFPhtml','activevfp.prg')
oCookie=NEWOBJECT('AVFPcookie','activevfp.prg')
oProp.ScriptPath=oRequest.servervariables("SCRIPT_NAME")
oProp.SessID=NVL(oRequest.querystring("sid"),"")
oProp.AppStartPath=JUSTPATH(oRequest.ServerVariables("PATH_TRANSLATED"))+[\] &&JUSTPATH(APPLICATION.SERVERNAME)+"\"
oProp.AppName=STREXTRACT(oRequest.ServerVariables("PATH_INFO"),[/],[/])  &&blank if installed to root &&JUSTSTEM(APPLICATION.SERVERNAME)
oProp.RunningPrg=[main.prg]

*-------+ START ...The following added by me 
**************************************************************
* REST-like APIs implementation
*
* Author: Victor Espina
* Date: April 2012
*
**************************************************************
* Create an instancia of RESTHelper class
LOCAL oRESTHelper, cRootPath
LOCAL lcHTMLout,lcHTMLfile, lnAppFunc
cRootPath = oRequest.serverVariables("APPL_PHYSICAL_PATH")
oRESTHelper = NEWOBJECT("restHelper","PRG\RESTHelper.PRG")
oRESTHelper.setFolder("ROOT", cRootPath)
oRESTHelper.setFolder("CONTROLLERS", ADDBS(cRootPath) + "prg/rest/controllers")

*oRESTHelper.loadControllers()

lnAppFunc =  JUSTPATH(oRequest.ServerVariables("PATH_TRANSLATED"))+[\]+"Prg\ApplicationFunctionsSM\applicationFunctions.prg" 
If !ProcedureIsSet(lnAppFunc)
    SET Procedure TO (lnAppFunc) additive
EndIf
 
* Use RESTHelper object to check if the request conforms a REST-like API call. If so, pass
* the request object to RESTHelper in order to let the right resource controller handle it.
IF oRESTHelper.isREST(oRequest)
 oProp.appStartPath = oRequest.serverVariables("APPL_PHYSICAL_PATH")
 lcHTMLout = oRESTHelper.handleRequest(oRequest, oProp)
 If ProcedureIsSet(lnAppFunc)
   Release Procedure (lnAppFunc)
 endif  
 RETURN lcHTMLout
ENDIF

* If the request was not a REST-like API call, check if MAIN.PRG exists in
* oProp.appStartPath. If it doesn't, we change oProp.appStartPath to point
* to app's root folder. This will avoid an innecessary "file not found" 
* error.
IF NOT FILE(oProp.appStartPath + "\PRG\MAIN.PRG")
 oProp.appStartPath = oRequest.serverVariables("APPL_PHYSICAL_PATH")
ENDIF

* If for some reason we can't find a valid processor, return
* an error message
IF NOT FILE(oProp.AppStartPath+'\prg\main.prg')
 lcHTMLout = "oRESTHelper: cannot find " + oProp.appStartPath+"\prg\main.prg"
 If ProcedureIsSet(lnAppFunc)
   Release Procedure (lnAppFunc)
 endif  
 RETURN lcHTMLout
ENDIF
**************************************************************
*-------+ End ...The above added by me 

lcScript=FILETOSTR(oProp.AppStartPath+'\prg\main.prg')
*lcHTMLout= EXECSCRIPT(lcScript) &&main()  && run the application
*RETURN lcHTMLout

*----- Nov 2013 .. Create a physical file on disk to enable better handler for debugging. 
LOCAL lcFile, lcFunctionName, lcFileFxp, lcEval, llError, oExp,lcErrMsg, lcFileBak

llError = .F.
*------+ Play safe for concurrent requests during peak usage times
Do WHILE .T.
    lcFunctionName = [p]+SYS(2015)
    lcFile = oProp.AppStartPath+[temp\]+lcFunctionName+[.prg]
    IF !FILE(lcFile)
        EXIT
    ENDIF
ENDDO       

lcEval = [Function ]+lcFunctionName+CHR(13)+CHR(10)+lcScript
STRTOFILE(lcEval,lcFile)
COMPILE (lcFile)
SET PROCEDURE TO (lcFile) ADDITIVE
                
Try
    lcHTMLout= &lcFunctionName()
Catch to oExp
    llError = .T.
finally
    *CLOSE DEBUGGER 
    Release PROCEDURE (lcFile)
    lcFileFxp = FORCEEXT(lcFile,"fxp")
    lcFileBak = FORCEEXT(lcFile,"Bak")
    TRY
        DELETE FILE(lcFile)
        DELETE FILE(lcFileFxp)
        DELETE FILE(lcFileBak)
    CATCH
        *-----+ Low level error..just keep going.. we'll handle it during directory cleanup
    EndTry
EndTry
If llError
    lcErrMsg = ''
    lcErrMsg = lcErrMsg + '<B>'+UPPER(oProp.RunningPrg)+'</B></br>'
    lcErrMsg = lcErrMsg + 'Procedure: ProxyStub Init-('+oExp.Procedure+')</br>'
    lcErrMsg = lcErrMsg + 'Error#: '+STR(oExp.ErrorNo,5)+'</br>'
    lcErrMsg = lcErrMsg + 'LineNo: '+STR(oExp.LineNo - 1 ,5)+'</br>'  
    lcErrMsg = lcErrMsg + 'Msg: '+oExp.Message+'</br>'
    lcErrMsg = lcErrMsg + 'Details: '+oExp.Details+'</br>'
    If _VFP.StartMode = 0 &&  !INLIST(_VFP.StartMode,3,5)
    lcErrMsg = lcErrMsg + 'LineContents: '+oExp.LineContents+'</br>'
    Endif
    lcErrMsg = lcErrMsg + 'ServerName: '+_VFP.SERVERNAME  
    If INLIST(_VFP.StartMode,3,5)
        *------+ Abort to COM client (i.e. ASP)
        COMreturnerror(lcErrMsg,_VFP.SERVERNAME)
    Else
            *-----+ Give error message but keep going.
            lcErrMsg = STRTRAN(lcErrMsg,'<B>','')
            lcErrMsg = STRTRAN(lcErrMsg,'</B>','')
            MESSAGEBOX(STRTRAN(lcErrMsg,'</br>',CHR(13)+CHR(10)))
    endif   
EndIf
If ProcedureIsSet(lnAppFunc)
  Release Procedure (lnAppFunc)
endif   
RETURN lcHTMLout

4) Add the following just below the line 'FUNCTION Process' in the proxystub.prg.

Note that this is only for debugging. you MUST comment out the entire portion in production. Also this may be the cause of thread aborting message. Better manner may be to make change in the asp dll itself (and I don't have ASP source code to do that). In fact if you start avfp, and if the following code has 'not' been commented out, then you will always get Run time error. To avoid this error, open VFP (as administrator) before running AVFP, in the manner documented for debugging V5.x

In fact I have this portion running based on an <appSettings> value in Web.Config.
FUNCTION Process

*-------+ START Delete this in Production...
Local loFox, lcASPDebugger, lnAppFunc, lProcIsSet
LOCAL lcHTMLout,lcHTMLfile

*lnAppFunc =  JUSTPATH(this.oRequest.ServerVariables("PATH_TRANSLATED"))+[\]+"Prg\ApplicationFunctionsSM\applicationFunctions.prg" 
*SET Procedure TO (lnAppFunc) additive

*If FILE(lnAppFunc)
    *lcASPDebugger = NVL(GetASPApplicationProperty("ASPDebugger",THIS.oRequest),"OFF")
    *If lcASPDebugger != "OFF"
        loFox = GETOBJECT(,"visualfoxpro.application.9")
        If VARTYPE(loFox) = "O"
            loFox = null
            Release loFox
            oProp=NEWOBJECT('AVFPproperties')  && create properties shared among classes
            lcHTMLout = this.Debugger()
            *If ProcedureIsSet(lnAppFunc)
            *   Release Procedure (lnAppFunc)
            *endif  
            Return lcHTMLout
        Endif
    *EndIf
*Endif
*-------+ END Delete this in Production...
5) Change the main.prg. Replace the 'otherwise' portion of the Case .. endcase as follows.
OTHERWISE   && get .avfp script
    
    *------+ Activate the debug thru VS 2012
    Do Case
    case LOWER(oProp.Action) == "default" and LOWER(oProp.Ext) == ".aspx"
            *----+ Oct 2013.. 
            oProp.Action =  "default"
            oProp.Ext = ".avfp"
            lcHTMLout= FILETOSTR(oProp.HtmlPath+oProp.Action+oProp.Ext)
            oProp.RunningPrg=oProp.Action+oProp.Ext
            lcHTMLout= oHTML.mergescript(lcHTMLout)
    case !ISNULL(oProp.Action)  .AND. FILE(oProp.HtmlPath+oProp.Action+oProp.Ext) 
        * This section must stay here for pure scripting mode
        lcHTMLout= FILETOSTR(oProp.HtmlPath+oProp.Action+oProp.Ext)
        oProp.RunningPrg=oProp.Action+oProp.Ext
        lcHTMLout= oHTML.mergescript(lcHTMLout)
    Otherwise
    *ELSE    && goto default page
*       USE mydbf  && test error
        CookieLogin()  && checks for cookie to authenticate
        lcHTMLfile = 'default'+oProp.Ext
        If !FILE(oProp.HtmlPath+lcHTMLfile)
            *----+ Oct 2013.. default document is not being served by IIS.. force it.
            Local lcPath
            lcPath = ALLTRIM(oRequest.ServerVariables("SCRIPT_NAME"))
            lcPath = lcPath + IIF(RIGHT(lcPath,1) != '/','/','')
            oResponse.Redirect(lcPath+'default.avfp')

        endif   
        lcHTMLout= FILETOSTR(oProp.HtmlPath+lcHTMLfile)
        oProp.RunningPrg=[default]+oProp.Ext
        lcHTMLout= oHTML.mergescript(lcHTMLout)
    *ENDIF
    Endcase
    
ENDCASE
6) To debug.. Follow the normal manner to open VS & VFP as adminstrator . However, you will need to open Default.aspx as a starting point to start debugging in VS. the contents of debug.aspx and default.aspx is the same.
Debug properties for VS 
Start Options -> Start action -> Use current page 
Start Options -> server -> Use default web server 
Start Options -> debugger -> asp.net. 
Build -> start action -> before running startup page: -> Nobuild 
Build-> target framework 4.5 -> .net framework 4.5 

In IIS manager, 
Application pool -> <select the application pool used by your application> ->Basic Settings-> set .net framework to 4.0 and pipeline to integrated.
Developer
May 28 at 4:29 PM
PAGE 3


7) I hope I have included all the changes.. I can debug the entire application except the PDF portion.. which starts its own automation server and therefore cannot be
debugged from ASP automation server.


8) Misc Points

If web site's 'application pool' is on .net ver 2, in integrated mode in IIS then it would still work.. but this creates htmlencoding holes. IIS should use the setting of .net ver 4 in integrated mode.

I've already updated the changes required in the web.config file. Note that we are now calling the images as static files in httpHandlers. If I missed any static file extension, then, it will need to be added in this section.


Also note that I have used both httphandlers ( which are related to .Net ver 2) and also handlers ( which are related to .net ver 3 or 4). This is done to handle Ajax calls.

Note that we have noticeable differences in IIS and .net development server. I did not try IIS Express.

Apart from deleting all web.config files ( except the web.config file in the application root), you can ( if you want to ), now revert these sub-directories to their 'non-application' states in IIS. To do this, go to the virtual 'sub' directory in IIS manager window, and do a right click, then click 'remove' in the context menu that comes up.

Also ensure that you have loaded the symbols in VS during debugging. If trace does not start in debug mode, then you try to force VS to reload by flipping the .net framework ...to something else and putting it back to original value after re-opening VS.

You may also try by copying the App_Code directory (along with contents) under your application root directory temporarily and start asp debug by setting a breakpoint in AVFPHandlers.cs file. App_code directory is under HTTP Handler directory of demo project.
Developer
May 28 at 4:45 PM
PAGE 4

That's all I can give at this time. Let me know if you want any clarifications.

Happy coding.. ;)
Coordinator
May 29 at 10:03 AM
Edited May 29 at 10:04 AM
THANK You so much for this information!!