Adventures on the edge

Learning new development technologies
    "When living on the bleeding edge - you sometimes have to bleed" -BillKrat

Easy steps to installing Node, NPM, TypeScript, and Bower in Windows


1.  https://chocolatey.org/ to install The package manager for Windows – click “Install Chocolatey Now” button.

2. Copy the cmd.exe or PowerShell.exe command line [following instructions] as applicable.

3. After installation is complete, exit and launch command prompt (CMD.EXE) – npm will now be available.

    a. npm install – g typescript

    b. npm install –g bower


More on


ApexLogMonitor for the Welkin Suite


I did some minor refactoring and 11 unit test broke - the Welkin Suite makes it simple to step through the code and view variables, but they can’t show me what they aren’t given – the information I need….  

Source code available at https://github.com/BillKrat/LogFolderMonitor  

My test is failing at line 420 but as you can see Salesforce truncates their text so I have no idea what “(28 more)” in the red box below actually means.  This was going to be problematic as this information will not only help me resolve my failures, but also help in creating new unit test (values to test for).   This was impacting my velocity so it was time to roll up my sleeves and crank out a little utility to rectify this.

001-expectedMessage

I created a log folder monitor that will open, parse, and display only the USER_DEBUG content as the log files are created.   This will aid immeasurably, particularly since I use IOC to inject values; it will help me see at a glance what implementation the factory served up for a given interface.   What I am interested in right now is what the friendly message contents are for line 420 above so I can get my test to pass (without digging through my code).  My logger implementation shows that I have “D”ebug statements as well as a “W”arning – it is that last warning I am interested in.  

Since the console is not easy to save (other than a screenshot) I added a “o” keypress option that will open the buffered data in the default editor configured to handle .TXT files.  I hit ‘o’ in the screenshot below and now can easily copy/paste what I need to fix the unit test.  

002-actualMessage

At a glance I can see the culprit was from my refactoring – I decided that for logging/internal message purposes I didn’t need to keep the LCPT prefix (since all my classes have it) so I stripped them off.   I have unit test that were looking for this (as was failing above) so this was a quick reminder how I can probably fix some of those 11 failing test.

To make the ApexLogMonitor easy to access I added it to “External Tools”, this way I can easily load it when I want to capture logging information.

003-Setup

Note: this C# console application does send all logging statements to the DEBUG output.  This means you can use a utility such as DebugView to see all of the logging information as it becomes available.   The DebugView utility has filtering capabilities so if you want to see only content for a given class you can do something similar to what I have below:

image

Using ApexDoc with Welkin Suite

The Welkin Suite Spire R4 (Version 1.1.3.4) Salesforce development platform has a very impressive set of features.  I particularly love the ability to step through my code using the debugger while viewing variables, seeing my code coverage for my unit test (in color), and the ease in which I can deploy from my sandbox to my developer environment (DE) without ever going to a command prompt – everything is point and click, high performance, and easy to use.

I did have a major set back on this last release.  When I right clicked on my class name I saw a feature called Generate Apex Doc For Current Context.  I wasn’t sure what this was, but after a little research found the source code on GitHub along with documentation – I was now going to have to redo all of my documentation…  The set back was not from having to support the ApexDoc format (the Welkin Suite made this easy), but the work I was going to have to do so that the apexdoc.jar application would work seamlessly from within the Welkin Suite.   This required me to add features to ApexDoc, released as GwnV1.x.

image

My source code fork of the ApexDoc application allowed me to do just this [while maintaining backwards compatibility] I added default features that only require the apexdoc.jar file to be dropped into the solution folder and three entries made to the External Tools menu – steps shown below.

To setup the Welkin Suite to use ApexDoc (GwnV1.x) do the following:

Add the apexdoc.jar application to the Welkin Suite Tools menu:

  1. Click on Tools
  2. Click on External Tools…
  3. Fill in the External Tools dialog as shown on the right

With the above settings in place you can select “DOCS: Execute ApexDoc” from the Tools menu which will execute apexdoc.jar using the default settings.

Note: the apexdoc.jar file needs to be place in the solution direction for the defaults to work correctly.

DocApex

001

Note: above I indicated that the apexdoc.jar file needs to be in the solution folder, to be clear it is assumed that you saved your .sfln file in the same folder as your project file (so that the src folder is at the root as shown below).   If you have multiple projects, each with their own documentation, then you will want to ensure an apexdoc.jar file is dropped into each project folder (or you can put apexdoc.jar in your path and configure the switches).

ApexDocLocation


Once the apexdoc.jar application is executed it will generate the applicable help files and place them in a folder called ApexDocumentation in the solution folder.

If your solution folder has a folder called ApexDocContent with the following files they will be automatically used:

  1. .header.html
  2. .home.html

The .header.html file contains the logo and heading information for your application help docs.  In the example below the logo for Global Webnet, LLC is shown.  The .home.html file will display on the “Home” (default) tab of the help page.

DocView

002


The final configuration made in external tools is for the “Edit” feature; this will permit you to easily edit the HTML content for your help pages.   In my case I am using Visual Studio Code, it is a free editor that easily handles html, css, and javascript.

I added ./ApexDocContent to the arguments of the code.exe application with a initial directory of the solution folder.   When it executes it loads the application ready to start editing the html documents used by the help system.
DocEdit

Note above [in the screen shot of the documentation] that I have a blue box around a @group Configuration tag and I configure the @group-content location to the ApexDocContent folder.   Below I created a configuration.html it will be looking for.

003

 

Below I show what the .home.html file looks like after editing it in the above window:

004

The solution folder for my CPT application has the apexdoc.jar java application and the ApexDocContent folder which the ApexDoc (GwnV1.x) has been revised to support.  These are the only additional requirements you will have to comply with to take advantage of the ApexDoc features

Click HERE to get the contents of the ApexDocContent folder as well as the latest apexdoc.jar file.

SolutionFolder

When the apexdoc.jar application is executed it will copy all files (that are not html documents) to the ApexDocumentation folder so that they are available for your documentation.   The html files are not copied because the ApexDoc application has already retrieved the information from them (between the body tags) and has inserted the content into documentation files in the ApexDocumentation folder using the same html filename – thus we need to ensure we don’t copy the html files over (the ApexDoc GwnV1.x application takes care of this for you).

The highlighted files below show the minimum files I recommend for your AppDocContent folder.  The css, js, and logo files can be updated and your updates will replace the ApexDocumentation files so that if you make updates you can utilize them in your documentation, e.g. for THIS PAGE I added magnifier .css and .js files. 

ApexDocContent

TDD - System.AggregateException : One or more errors occurred.

The context of this blog is all unit test failing in Resharper… Adventures on the edge

My environment is Visual Studio 2015 Update 3 using Resharper Ultimate.  I see the following message before the system starts shutting down and failing all unit test

TakingLong

I then see the following dialog box Adventures on the edge

CannotLaunch

The clue to resolving this came from the first dialog (above).  I tried setting the following “Options”:

  • Platform: 32-bit
  • Framework: CLR4.5 [not sure if this is optional]

And my test started working!

Fix

Does not implement inherited abstract member 'HttpContent.SerializeToStreamAsync(Stream, TransportContext)

So what is wrong with the following code?

It should compile, I’ve seen identical code on an internet blog suggesting it should work.  I delete the offending method SerializationToStreamAsync and have Visual Studio generate it from the interface – it produces the same issue.

It should work – but it doesn’t, keep reading for the solution!

CannotOverride

I resolved the issue in 3 easy steps, after numerous long hours of research….

First, I had to remove the existing System.Net references,  second I loaded NuGet Package manager, and finally I browsed for and installed the v4.1.0 version of the System.Net.Http package and the problem was resolved – I could now compile my solution successfully!

Fix

 

using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace Salesforce.Force.UnitTests
{
internal class JsonContent : HttpContent
{
private readonly MemoryStream _stream = new MemoryStream();
public JsonContent(object value)
{

Headers.ContentType = new MediaTypeHeaderValue("application/json");
var jw = new JsonTextWriter(new StreamWriter(_stream))
{
Formatting = Formatting.Indented
};
var serializer = new JsonSerializer();
serializer.Serialize(jw, value);
jw.Flush();
_stream.Position = 0;
}
protected JsonContent(string content)
{
Headers.ContentType = new MediaTypeHeaderValue("application/json");
var sw = new StreamWriter(_stream);
sw.Write(content);
sw.Flush();
_stream.Position = 0;
}
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
return _stream.CopyToAsync(stream);
}
protected override bool TryComputeLength(out long length)
{
length = _stream.Length;
return true;
}
public static HttpContent FromFile(string filepath)
{
string content = File.ReadAllText(filepath);
return new JsonContent(content);
}
}
}