<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Software Development &#8211; XtremeOwnage</title>
	<atom:link href="https://xtremeownage.com/category/technology/software-development/feed/" rel="self" type="application/rss+xml" />
	<link>https://xtremeownage.com</link>
	<description>Cars, Computers, and Code.</description>
	<lastBuildDate>Sun, 08 Jan 2023 02:09:05 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.4.3</generator>

<image>
	<url>https://xtremeownage.com/wp-content/uploads/2019/09/cropped-Turbo-512-2-100x100.png</url>
	<title>Software Development &#8211; XtremeOwnage</title>
	<link>https://xtremeownage.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>C# &#8211; Dynamically Invoking Method on RuntimeTypes</title>
		<link>https://xtremeownage.com/2019/12/20/c-dynamically-invoking-method-on-runtimetypes/</link>
					<comments>https://xtremeownage.com/2019/12/20/c-dynamically-invoking-method-on-runtimetypes/#comments</comments>
		
		<dc:creator><![CDATA[XO]]></dc:creator>
		<pubDate>Fri, 20 Dec 2019 21:35:53 +0000</pubDate>
				<category><![CDATA[C# / .Net]]></category>
		<guid isPermaLink="false">https://xtremeownage.com/?p=787</guid>

					<description><![CDATA[Dynamically invoking methods on Types resolved at runtime via Attributes.]]></description>
										<content:encoded><![CDATA[
<p>I have an interesting project I set out to create today-</p>



<p><br>I wanted to build a simple page, which would allow our NOC to trigger certain workflows, automatically (assuming they have proper permission)</p>



<p>My requirements:</p>



<ol><li>Jobs should be easily added to the list, just by specifying an Attribute, and Implementing an interface (to ensure the proper method exists)</li><li>Jobs needs to be kicked off on my back-end servers and not on the web-front end.</li><li>Everything needs to be properly logged.</li><li>The front-end needs visual-feedback a job has been executed.</li></ol>



<p></p>



<h3 class="wp-block-heading">Here is the web page to trigger jobs.</h3>



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1335" height="423" src="https://i2.wp.com/xtremeownage.com/wp-content/uploads/2019/12/NOC-Automation-Page.png?fit=1024%2C324&amp;ssl=1" alt="" class="wp-image-789" srcset="https://xtremeownage.com/wp-content/uploads/2019/12/NOC-Automation-Page.png 1335w, https://xtremeownage.com/wp-content/uploads/2019/12/NOC-Automation-Page-300x95.png 300w, https://xtremeownage.com/wp-content/uploads/2019/12/NOC-Automation-Page-1024x324.png 1024w, https://xtremeownage.com/wp-content/uploads/2019/12/NOC-Automation-Page-768x243.png 768w" sizes="(max-width: 1335px) 100vw, 1335px" /></figure>



<p>As you can see, the above page is very simple.</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1194" height="423" src="https://i2.wp.com/xtremeownage.com/wp-content/uploads/2019/12/Job-Triggered.png?fit=1024%2C363&amp;ssl=1" alt="" class="wp-image-790" srcset="https://xtremeownage.com/wp-content/uploads/2019/12/Job-Triggered.png 1194w, https://xtremeownage.com/wp-content/uploads/2019/12/Job-Triggered-300x106.png 300w, https://xtremeownage.com/wp-content/uploads/2019/12/Job-Triggered-1024x363.png 1024w, https://xtremeownage.com/wp-content/uploads/2019/12/Job-Triggered-768x272.png 768w" sizes="(max-width: 1194px) 100vw, 1194px" /><figcaption>When a job is successfully triggered, the button will turn green, and it will be disabled.</figcaption></figure>



<p>In the above image, if a job fails, it will turn red, with direction to call the developers (me).</p>



<h2 class="wp-block-heading">How it works (Short Version)</h2>



<p>At startup, Reflection is used to build a dictionary containing types which implement IRemoteJob interface, and the NocJob attribute. </p>



<p>A webpage displays the values. Permissions are implemented at the controller level.</p>



<p>When a job is triggered, the Type&#8217;s full name is passed back to the method. The method will compare the provided name, against the dictionary of valid workflows. If the workflow is found, and verification passes, <a href="http://hangfire.io">Hangfire.Io</a> is then used to execute the workflow on my backend- automation services away from the web front end.</p>



<p>Since- we cannot execute a string containing the name of a type&#8230; We utilize Ninject&#8217;s kernel to resolve a instance of the class. We then Invoke the execute method, which is defined by the IRemoteJob interface, on the class instance.</p>



<p>Error handling is handed by Hangfire.</p>



<p>In short- that is it.</p>



<h2 class="wp-block-heading">How it works (Long Version)</h2>



<h4 class="wp-block-heading">RuntimeTypeResolver.cs // IRunTimeTypeResolver</h4>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    public class RuntimeTypeResolver : IRuntimeTypeResolver
    {
        private IKernel kernel;
        public RuntimeTypeResolver(IKernel Kernel)
        {
            this.kernel = Kernel;
        }
        public object GetInstanceOfType(Type type)
        {
            return kernel.Get(type);
        }
    }</pre>



<p>This class, resolves a class instance from the Ninject kernel and returns it.</p>



<h4 class="wp-block-heading">JobHelper.cs</h4>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">//Note - Singleton class.
    public class JobHelper
    {
        //IRunTimeTypeResolver passes a Type into a dependancy injection kernel. The kernel will return a instance of the Type.
        private IRuntimeTypeResolver rtr;
        public JobHelper(IJobScheduler JOB, IRuntimeTypeResolver RTR)
        {
            this.rtr = RTR;
            //Note- Dictionary only needs to be populated at startup.

            //Create a dictionary containing all eligible classes to be executed ad-hoc.
            RemoteJobs = this.GetType() //Types are filtered to this current assembly.
                .Assembly
                .GetTypes()
                //Type/Class implements IRemoteJob interface, and is NOT an interface or abstract class.
                .Where(x => (typeof(IRemoteJob).IsAssignableFrom(x) &amp;&amp; !x.IsInterface &amp;&amp; !x.IsAbstract))
                //Class has the NocJobAttribute, which contains display information.
                .Where(x => Attribute.IsDefined(x, typeof(NocJobAttribute)))
                //Cast the types, and create a dictionary.
                .ToDictionary(o => (NocJobAttribute)Attribute.GetCustomAttribute(o, typeof(NocJobAttribute)), o => o);
        }

        //A read-only dictionary containing the information. 
        public IReadOnlyDictionary&lt;NocJobAttribute, Type> RemoteJobs { get; }

        /// &lt;summary>
        /// This is intended as an entry point for background jobs. 
        /// &lt;/summary>
        /// &lt;param name="JobName">&lt;/param>
        public void EnqueueRemoteJob(string JobName)
        {
            //Get the Type from the list.
            Type Rec = RemoteJobs
               .First(o => o.Value.FullName.Equals(JobName, StringComparison.OrdinalIgnoreCase))
               .Value;

            //Get the Execute method. It should exist, because all items in this list, implement IRemoteJob.
            MethodInfo ExecuteMethod = Rec.GetRuntimeMethod("Execute", new Type[] { });

            //Get a instance of the type, from the RuntimeTypeResolver class.
            object Instance = rtr.GetInstanceOfType(Rec);

            //Invoke the Execute Method on the class instance.
            ExecuteMethod.Invoke(Instance, null);
        }
    }</pre>



<p>The primary purpose of this job, is to both hold a list of &#8220;valid&#8221; workflows which can be executed, and to expose a method which the Hangfire.io can trigger with the Type&#8217;s name, to invoke the workflow.</p>



<h4 class="wp-block-heading">JobController.cs &#8211; Trigger_NOC_Job method</h4>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">        [HttpPost]
        [CheckPermissionAttribute(Permission.Trigger_AutomationJobs)]
        public ActionResult Trigger_NOC_Job(string JobType)
        {
            log.Component = "Trigger";
            var L = new JobTriggerLog
            {
                JobName = new string[] { JobType },
                Time = DateTime.Now,
                UserID = User.Identity.Name,
                UserName = User.GetFullName()
            };
            try
            {
                //now the FUN part...
                if (!jobHelper.RemoteJobs.Any(o => o.Value.FullName.Equals(JobType, StringComparison.OrdinalIgnoreCase)))
                {
                    L.Error = new Exception("Job was not located.").GetUsefulDetails(false);
                    log.Error(L);
                    return new HttpStatusCodeResult(System.Net.HttpStatusCode.NotFound, "Job was not found.");
                }

                //Get the Type from the list.
                Type Rec = jobHelper
                   .RemoteJobs
                   .First(o => o.Value.FullName.Equals(JobType, StringComparison.OrdinalIgnoreCase))
                   .Value;

                //Sanity check to double-check the Execute method exists, without required parameters.
                if (Rec.GetRuntimeMethod("Execute", new Type[] { }) == null)
                    throw new NullReferenceException("Execute method was not found on job.");

                //Use IJobScheduler to enqueue the job on the backend automation services.
                job.Enqueue&lt;JobHelper>(o => o.EnqueueRemoteJob(JobType));

                log.Success(L);

                return Json(true);
            }
            catch (Exception ex)
            {
                L.Error = ex.GetUsefulDetails();
                log.Error(L);
                return new HttpStatusCodeResult(System.Net.HttpStatusCode.InternalServerError, $"Something went wrong. {ex.Message}");
            }
            finally
            {
                log.SendLogSession();
            }
        }</pre>



<p>This is the api which is called when a user would like to trigger a workflow.</p>



<h2 class="wp-block-heading">Why is this interesting?</h2>



<p>Creating a method for each action is easy to do. Creating a single method which can dynamically invoke class instances at runtime, while resolving all of their dependencies, and following your current error handling strategies- isn&#8217;t quite so easy. <br><br>This process- allows me as the developer, to quickly, and easily add new workflows / jobs to the NOC visible page. The NOC can easily trigger the jobs&#8230;. and the process of creating the class instances, resolving dependencies&#8230;. is all auto-magically handled by the dependency injection framework.</p>



<p>As well, I have not posted anything in a while, and I felt this was interesting enough to share.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://xtremeownage.com/2019/12/20/c-dynamically-invoking-method-on-runtimetypes/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Visual Studio / Git &#8211; Moving commits to another branch via Cherry-Pick</title>
		<link>https://xtremeownage.com/2019/10/29/visual-studio-git-moving-commits-to-another-branch-via-cherry-pick/</link>
		
		<dc:creator><![CDATA[XO]]></dc:creator>
		<pubDate>Tue, 29 Oct 2019 19:28:42 +0000</pubDate>
				<category><![CDATA[Git / Source Control]]></category>
		<category><![CDATA[Software Development]]></category>
		<guid isPermaLink="false">https://xtremeownage.com/?p=735</guid>

					<description><![CDATA[Accidentally write code on the master branch, and need to move it to another branch? How to Cherry-pick your commits to another branch.]]></description>
										<content:encoded><![CDATA[
<p>Ever have the problem where you were not paying attention, and you created a few commits on the MASTER branch, instead of a feature branch? </p>



<p>No worries- I just made that exact same mistake, and I am going to demonstrate how to resolve the issue&#8230;.</p>



<p>In the below image, you can see&#8230;. I accidentally made my commits to the master branch, instead of my feature/dev/test branch. Instead of redoing all of the commits manually, I am going to demonstrate the cherry-pick method for manually moving the commits over.</p>



<figure class="wp-block-image"><a href="https://xtremeownage.com/wp-content/uploads/2019/10/1.-Oops.png" rel="prettyPhoto[gallery-01ew]"><img decoding="async" width="420" height="468" src="https://xtremeownage.com/wp-content/uploads/2019/10/1.-Oops.png" alt="" class="wp-image-737" srcset="https://xtremeownage.com/wp-content/uploads/2019/10/1.-Oops.png 420w, https://xtremeownage.com/wp-content/uploads/2019/10/1.-Oops-269x300.png 269w" sizes="(max-width: 420px) 100vw, 420px" /></a><figcaption>Uh-oh, I accidentally commited my changes to master&#8230;.</figcaption></figure>



<h2 class="wp-block-heading">Method: Cherry Pick Commits to new branch</h2>



<p>For method one, I will demonstrate cherry-picking the specific commits, into the proper branch.</p>



<h4 class="wp-block-heading">Step 1: Take note of the specific commits.</h4>



<p>In my example, I need to move these commits:</p>



<ul><li>dda291d4 &#8211; Update LIB.Interfaces</li><li>d46a4441 &#8211; The lastExecutionIdParameter&#8230;.</li></ul>



<p>I am leaving out the &#8220;merge branch &#8216;master'&#8221;commit, because, the new branch is already up to date with master.</p>



<h4 class="wp-block-heading">Step 2: Create new branch, or switch to the proper branch.</h4>



<figure class="wp-block-image"><a href="https://xtremeownage.com/wp-content/uploads/2019/10/2.-Create-New-Branch-or-Select-Proper-Branch.png" rel="prettyPhoto[gallery-01ew]"><img loading="lazy" decoding="async" width="449" height="611" src="https://xtremeownage.com/wp-content/uploads/2019/10/2.-Create-New-Branch-or-Select-Proper-Branch.png" alt="" class="wp-image-738" srcset="https://xtremeownage.com/wp-content/uploads/2019/10/2.-Create-New-Branch-or-Select-Proper-Branch.png 449w, https://xtremeownage.com/wp-content/uploads/2019/10/2.-Create-New-Branch-or-Select-Proper-Branch-220x300.png 220w" sizes="(max-width: 449px) 100vw, 449px" /></a><figcaption>Create a new branch, or select the proper branch.</figcaption></figure>



<h4 class="wp-block-heading">Step 3. Cherry pick the individual commits</h4>



<p>While this functionality is likely built into visual studio somewhere, I chose the command line terminal to perform the cherry-pick.</p>



<p>If you do not have git in your path variable, you may use the visual studio Nuget package manager console to perform these changes.</p>



<figure class="wp-block-image"><a href="https://xtremeownage.com/wp-content/uploads/2019/10/3.-Cherry-Pick-Commits.png" rel="prettyPhoto[gallery-01ew]"><img loading="lazy" decoding="async" width="979" height="511" src="https://xtremeownage.com/wp-content/uploads/2019/10/3.-Cherry-Pick-Commits.png" alt="" class="wp-image-739" srcset="https://xtremeownage.com/wp-content/uploads/2019/10/3.-Cherry-Pick-Commits.png 979w, https://xtremeownage.com/wp-content/uploads/2019/10/3.-Cherry-Pick-Commits-300x157.png 300w, https://xtremeownage.com/wp-content/uploads/2019/10/3.-Cherry-Pick-Commits-768x401.png 768w" sizes="(max-width: 979px) 100vw, 979px" /></a><figcaption>git cherry pick command</figcaption></figure>



<h4 class="wp-block-heading">Done!</h4>



<figure class="wp-block-image"><a href="https://xtremeownage.com/wp-content/uploads/2019/10/4.-Done.png" rel="prettyPhoto[gallery-01ew]"><img loading="lazy" decoding="async" width="414" height="356" src="https://xtremeownage.com/wp-content/uploads/2019/10/4.-Done.png" alt="" class="wp-image-740" srcset="https://xtremeownage.com/wp-content/uploads/2019/10/4.-Done.png 414w, https://xtremeownage.com/wp-content/uploads/2019/10/4.-Done-300x258.png 300w" sizes="(max-width: 414px) 100vw, 414px" /></a><figcaption>Voila- commits are now on the proper branch.</figcaption></figure>



<p>After cherry-picking the individual commits to the new branch, you are done!</p>



<p>Make sure to rebuild with the updated code, to ensure you didn&#8217;t leave something out.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>c# &#8211; Paging Urls using abstraction and generics</title>
		<link>https://xtremeownage.com/2019/10/08/c-paging-urls-using-abstraction-and-generics/</link>
		
		<dc:creator><![CDATA[XO]]></dc:creator>
		<pubDate>Tue, 08 Oct 2019 18:59:06 +0000</pubDate>
				<category><![CDATA[C# / .Net]]></category>
		<guid isPermaLink="false">https://xtremeownage.com/?p=536</guid>

					<description><![CDATA[Despite the nasty sounding title, this post will demonstrate an easy method to abstract the paging of an applications URL. For my particular use-case, I need to retrieve many records...]]></description>
										<content:encoded><![CDATA[
<p>Despite the nasty sounding title, this post will demonstrate an easy method to abstract the paging of an applications URL.</p>



<p>For my particular use-case, I need to retrieve many records from an application called <a href="https://www.rapid7.com/">Rapid7</a> for the purpose of exporting the data into Splunk. To do this successfully, I will need to query 5 or 10 separate tables, and I will need to page the results for each table.</p>



<p>I am sure many of you have written logic like this before, and included the paging logic directly in the method for each table. Myself- I am a huge fan of writing simple, clean abstracted code, which is easy to read&#8230; Since, this will be mostly the same logic, over and over&#8230; It makes sense</p>



<h4 class="wp-block-heading">Application Logic</h4>



<p>I like to have a strong separation between the &#8220;What&#8221; the workflow is doing, and &#8220;How&#8221; it is accomplished. I handle this by using copious amounts of abstraction. Here is the main logic:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">        public async Task Execute(IJobCancellationToken jobCancellationToken)
        {
            try
            {
                //var splunk = log.CreateSplunkTarget(splunk_Index, null, splunk_Source);

                int TotalAssetCount = 0;
                await foreach (var asset in PageAllResults(GetAsset, jobCancellationToken.ShutdownToken))
                {
                    TotalAssetCount++;
                }


                int total_Exceptions = 0;
                await foreach (var asset in PageAllResults(GetVulnerability_Exceptions, jobCancellationToken.ShutdownToken))
                {
                    total_Exceptions++;
                }

                //For testing- Output results to console for validation testing. 
                Console.WriteLine(TotalAssetCount);
                Console.WriteLine(total_Exceptions);
            }
            catch (OperationCanceledException)
            {
                if (jobCancellationToken.ShutdownToken.IsCancellationRequested)
                {
                    log.Warning("Workflow was cancelled.");
                    return;
                }
                throw; //Let the normal exception handler handle this.... since cancellation was not requested.
            }
            catch (Exception ex)
            {
                //Log the exception as fatal error.
                log.Fatal(ex.GetUsefulDetails());

                //Throw the exception to allow the job scheduler to handle the retry logic.
                throw;
            }
            finally
            {
                //This will invoke the logic to send out error emails to subscribers to this workflow.
                log.SendLogSession();
            }
        }</pre>



<p>For this article, it is only currently doing a count of the records returned. </p>



<p>You will notice the IJobCancellationToken. All of my &#8220;Automation Jobs&#8221; are configured with the idea in mind, that the server, or service, or job may need to be cancelled at any time. If any of those events happens to occur, The cancellationToken is passed down to allow a graceful stop of the application.</p>



<p>The logic executing this code contains the logic to automatically re-enqueue the job on another server when the previous job is cancelled.</p>



<h2 class="wp-block-heading">How to abstract paging the results of multiple method calls</h2>



<p>Next up- we will look at a method whose sole purpose, is to page the results of a method. This method is tailored specifically to this class, and prevents us from repeating the paging logic for each api(over 15 in total).</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">private async IAsyncEnumerable&lt;T> PageAllResults&lt;T>(Func&lt;int, CancellationToken, Task&lt;Wrapper&lt;T>>> action, [EnumeratorCancellation]CancellationToken ct) where T : class
        {
            bool HasMoreRecords = true;
            int Start = 0;

            do
            {
                var Results = await action.Invoke(Start, ct).ConfigureAwait(false);

                foreach (var a in Results.Resources)
                {
                    yield return a;
                }

                HasMoreRecords = Start &lt; Results.Page.TotalPages;
                Start++;
            }
            while (HasMoreRecords);
        }</pre>



<p>While the method signature may look scary- It is actually very simple to utilize. This method contains the application API-specific logic to handle paging for all of the GET requests we will be performing.</p>



<h4 class="wp-block-heading">Methods for specific APIs</h4>



<p>For the individual APIs, While I could abstract this logic into a dictionary, I decided to leave everything into its own individual method to allow me to easily document and customize the parameters per call. As well- if I need to intercept the results, and perform modification on the fly, it would allow me to easily contain the logic here. There will be around 15+ of these in total.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">        private Task&lt;Wrapper&lt;Asset>> GetAsset(int Start, CancellationToken ct)
        {
            //https://help.rapid7.com/insightvm/en-us/api/index.html#operation/getAssets
            var uri = new UriBuilder("https", baseUri, 443, "/api/3/assets");
            uri.Query = $"page={Start}&amp;size={50}&amp;sort=idASC";

            return QueryRapid7_GET&lt;Asset>(uri.Uri, ct);
        }

        private Task&lt;Wrapper&lt;Vulnerability_Exception>> GetVulnerability_Exceptions(int Start, CancellationToken ct)
        {
            //https://help.rapid7.com/insightvm/en-us/api/index.html#operation/getVulnerabilityExceptions
            var uri = new UriBuilder("https", baseUri, 443, "/api/3/assets");
            uri.Query = $"page={Start}&amp;size={500}&amp;sort=idASC";

            return QueryRapid7_GET&lt;Vulnerability_Exception>(uri.Uri, ct);
        }</pre>



<p>You will notice- The entire purpose of this method, is focused specifically how to obtain the results for the provided API. It does not contain the paging logic, or even the logic on how to perform the GET request. This allows for less code-duplication overall, which leads to a simpler product.</p>



<p>Lastly- In the current implementation of these two tables, it does not use Async. Rather, it passes the Task back to the calling method, without waiting for it to complete.</p>



<h2 class="wp-block-heading">Lastly- Abstractions for performing the request.</h2>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">        private async Task&lt;Wrapper&lt;T>> QueryRapid7_GET&lt;T>(Uri Uri, CancellationToken ct) where T : class
        {
            string credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(creds.UserName + ":" + creds.Password));

            var obj = await rest.GetObjectAsync&lt;Wrapper&lt;T>>(Uri, HttpMethod.Get, ct, RequestBody: null, Configure: o =>
           {
               o.Headers[HttpRequestHeader.Authorization] = $"Basic {credentials}";
           }).ConfigureAwait(false);


            if (obj.Exception != null)
                throw obj.Exception;

            return obj.Object;
        }</pre>



<p>The purpose of this method, is similarly to perform a GET query against the rapid7 API. To perform the query, it only needs to know the Uri, and the credentials (which are set by the constructor.).</p>



<p>Again- there is no logic for creating the URI specific to the endpoint, There is no logic for paging. The only logic contained in the method, is to perform a GET query against the provided URI.</p>



<p>Both error handling and CancellationTokens are built into my RestHelper class. This allows graceful cancellation of the workflows, as well as- allowing me to seperate my logic, from my error handling.</p>



<h2 class="wp-block-heading">Why Would I do that? That looks complicated!</h2>



<p>Because when this workflow is expanded to perform logic on each of the hundred+ APIs offered- The code will remain very readable with minimal repeated logic.</p>



<p>Each method is very specific to its own purpose, with as little overlap as possible. The end result, will be cleaner code, with less wasted room.</p>



<p>Now- if you job rates you based on lines of code written, by all means- Don&#8217;t abstract at all. Copy and paste everything!</p>



<p>However- if you like building supportable software, Separating areas of functionality will allow you to build a much more supportable product. As well, it is much easier to write a unit test for your methods, when they are responsible for performing a single task.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>ServiceNow &#8211; Query Every Asset A user has ever been assigned to</title>
		<link>https://xtremeownage.com/2019/10/03/servicenow-query-every-asset-a-user-has-ever-been-assigned-to/</link>
		
		<dc:creator><![CDATA[XO]]></dc:creator>
		<pubDate>Thu, 03 Oct 2019 19:17:53 +0000</pubDate>
				<category><![CDATA[ServiceNow]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[servicenow]]></category>
		<category><![CDATA[sys_audit]]></category>
		<category><![CDATA[sys_history]]></category>
		<category><![CDATA[sys_user]]></category>
		<guid isPermaLink="false">https://xtremeownage.com/?p=462</guid>

					<description><![CDATA[A method to query every asset that has ever been assigned to a list of users.]]></description>
										<content:encoded><![CDATA[
<p>So, an interesting request came across my desk earlier today, to query every asset a user has ever been assigned.</p>



<p>Normally- I would say this should be an easy request&#8230; Query sys_audit where tablename=alm_asset, fieldname=assigned_to,  filter by the values&#8230; and build a report based on this data.</p>



<p>However- data in sys_audit, stays forever, for every single table. So, if you attempt to run that query on any service-now instance that has been up for a few years, You will notice, it crashes.</p>



<p>This is because neither fieldname, nor tablename are indexed columns (on the underlying database)</p>



<p>However- if you look at an asset, and select history, this data is being pulled from sys_audit. </p>



<p>You may ask, well- why does that work when I cannot query the table at all??</p>



<p>The answer is- sys_audit.documentkey is an indexed field. So- when the related query looks for sys_audit where document_key = sys_id of the alm_asset, it returns very quickly, because it is indexed.</p>



<p></p>



<p>Now that we have gotten that part out of the way&#8230;. What about the report?</p>



<p>Well- while I am very knowledgeable on the BACKEND of service-now, and its available APIs, I do not know enough knowledge to build the query within service-now. BUT- I did create the logic in c# using a service-now library which I have created.</p>



<p>If you are a experienced service-now individual, you may be able to build a report based on my logic.</p>



<pre class="wp-block-code"><code lang="csharp" class="language-csharp">var Users = sn.OfType&lt;sys_user>().Where(o => (Insert lamba expression here to locate the specific users)).ToList();

foreach (var rec in sn.OfType&lt;alm_asset>())
{
    var history = sn.OfType&lt;sys_audit>()
        .Where(o => o.documentkey == (object)rec.sys_id)
        .Where(o => o.fieldname == nameof(alm_asset.assigned_to) || o.fieldname == nameof(alm_asset.u_custom_assigned_to))
        //Force query to list.
        .ToList()
        //Local Expression
        .Where(o => Users.Any(usr => usr.sys_id.Equals(o.newvalue)));

    foreach (var match in history)
    {
        //Do Something with you results.
    }
}</code></pre>



<p>The above query is quite inefficient, because it pulls down ALL assigned_to history change records for every asset to evaluate locally. However- it is many times faster then attempting to query sys_audit directly.</p>



<p>sys_history only contains 28 days of data, before any mentions it.</p>



<p>Summary:</p>



<ol><li>Query all assets</li><li>For each asset, query sys_audit where documentkey = asset.sys_id</li><li>Perform additional filtering on sys_audit, for specific field names, or values.</li><li>Profit.</li></ol>



<p>Edit- as a last note, this could easily be implement in service-now javascript.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
