Wednesday, January 3, 2018

One Solitary Life

He was born in an obscure village, the child of a peasant. He grew up in another village, where he worked in a carpenter shop until he was thirty. Then, for three years, he was an itinerant preacher.

He never wrote a book. He never held an office. He never had a family or owned a home. He didn't go to college. He never lived in a big city. He never traveled two hundred miles from the place where he was born. He did none of the things that usually accompany greatness. He had no credentials but himself.

He was only thirty-three when the tide of public opinion turned against him. His friends ran away. One of them denied him. He was turned over to his enemies and went through the mockery of a trial. He was nailed to a cross between two thieves. While he was dying, his executioners gambled for his garments, the only property he had on earth. When he was dead, he was laid in a borrowed grave, through the pity of a friend.

Twenty centuries have come and gone, and today he is the central figure of the human race. I am well within the mark when I say that all the armies that ever marched, all the navies that ever sailed, all the parliaments that ever sat, all the kings that ever reigned, put together, have not affected the life of man on this earth as much as that one, solitary life.
- James Allan Francis, One Solitary Life

Saturday, April 15, 2017

He Has Risen

It's around 5:00 AM in Jerusalem as I write this post, and all I can think about is the women arriving at the empty tomb of Jesus Christ.

The women were terrified and bowed with their faces to the ground. Then the men asked, “Why are you looking among the dead for someone who is alive? He isn’t here! He is risen from the dead!”
- Luke 24 5-6
Why are you looking among the dead for someone who is alive? Can you imagine that moment? Not even death could keep our Messiah from fulfilling His mission. I think about it all the time. Starting with the moment He prayed in the Garden of Gethsemane. Two chapters earlier in Luke 22:41 we hear "Then Jesus went about a stones throw away from them. He kneeled down and prayed." This was the final prayer of Jesus before He would be arrested, beaten, tortured, and sent to the cross. What's more remarkable is that He is praying for us. How do we know this? In Luke 22:42, Jesus asks God to take the cup of suffering away — yet when told "No", Jesus is still willing to go to the cross — for us!

Then I think about Jesus on the cross in Luke 23:34 when Jesus said "Father, forgive them, for they don't know what they are doing." Is that not representative of a Messiah that you want to follow? Christ Jesus praying for the men who tortured him, mocked him, and nailed Him to the cross.

Then in the Gospel of Matthew we read the following:

About three in the afternoon Jesus cried out in a loud voice, "Eli, Eli, lema sabachthani?" (which means "My God, my God, why have you forsaken me?").
- Matthew 27:46
This was a verse I used to struggle with. For the longest time I didn't take the time to understand what it meant, or why Jesus would cry out those words, or why God would forsake Jesus. But think about the moment Jesus took His final breath:

When Jesus had tasted it, he said, "It is finished!" Then he bowed his head and released his spirit.
- John 19:30
How was it possible for Jesus to feel that sense of abandonment? In that moment Jesus Christ took on all the sin of the world. Your sin. My sin. All sin. God simply had to look away for that singular moment when Jesus Christ carried the weight of all sin.

It's certainly worth noting that Jesus was also quoting Psalm 22:1, which is just further proof that He matched the prophetic fingerprint from the Old Testament of the coming Messiah . But we have to remember that Jesus was a human being, and this act of calling out to God was representative of our mortal struggle against death. Of course Christ wanted there to be another way. But there wasn't. We know that from Luke 22:42: "Father, if you are willing, please take this cup of suffering away from me. Yet I want your will to be done, not mine." Jesus didn't want to die. But that's what is the most remarkable part of it... He chose to die anyway.

But make no mistake, although God may have looked away as Jesus cried out and took His last breath, there was no separation between God and Jesus Christ. There simply was no other way to pay the debt of our sin. A perfect sacrifice was required. Jesus Christ was the only person who could save us. He lived the life we should have lived. He died the death we should have died. He saved us from the snares of hell and overcame death. Why? One word. Love.

Nothing we do will ever — ever —  and I mean ever, be sufficient to repay the debt that Jesus Christ paid for our sins —  yet He still pursues us relentlessly. He still extends grace and mercy to each of us. He still offers us all the chance to have a personal relationship with Him. Stop and think about that! You have the opportunity to have a personal relationship with Jesus Christ. All it takes is an invitation. And the invitation isn't from Jesus. It's from you! All you have to do is ask Jesus to be your Lord and Savior. To come in to your heart. It may not be easy. But it's that simple. And here's the best part. You don't have to have it all figured out to put your trust in Christ. It starts with a single act of obedience.

Taste and see that the LORD is good; blessed is the one who takes refuge in him.
- Psalm 34:8
As I reflect on the Resurrection this evening, I can't help but think about the lyrics to one of my favorite songs that we sang tonight at church, and when I say "sang", picture a thousand people standing and worshiping in awe, at the grace, mercy, and love that Christ showed for us when death was arrested and my life began.

Death Was Arrested
https://www.youtube.com/watch?v=m1fEJC0JtBw

[Verse 1]
Alone in my sorrow and dead in my sin
Lost without hope with no place to begin
Your love Made a way to let mercy come in
When death was arrested and my life began

[Verse 2]
Ash was redeemed only beauty remains
My orphan heart was given a name
My mourning grew quiet my feet rose to dance
When death was arrested and my life began

[Chorus]
Oh your grace so free
Washes over me
You have made me new
Now life begins with you
It's your endless love
Pouring down on us
You have made us new
Now life begins with you

[Verse 3]
Released from my chains I'm a prisoner no more
My shame was a ransom he faithfully bore
He cancelled my debt and he called me his friend
When death was arrested and my life began

[Verse 4]
Our savior displayed on a criminal's cross
Darkness rejoiced as though heaven had lost
But then Jesus arose with our freedom in hand
That's when death was arrested and my life began
That's when death was arrested and my life began

[Chorus]
Oh your grace so free
Washes over me
You have made me new
Now life begins with you
It's your endless love
Pouring down on us
You have made us new
Now life begins with you

[Bridge]
We're free free
Forever we're free
Come join the song
Of all the redeemed
Yes we're free free
Forever amen
When death was arrested and my life began
(2x)
When death was arrested and my life began
That's when death was arrested and my life began

Friday, December 16, 2016

ASP.Net C# Convert HTML to PDF using iTextSharp (update)

Here's a minor update to a post from last year how how to convert HTML to PDF using iTextSharp.

I wanted to add a way to optionally render the PDF in landscape mode, so this was what I ultimately came up with.

 public static ReturnValue ConvertHtmlToPdfAsBytes(string HtmlData, bool Landscape = false)
{
    // variables
    ReturnValue Result = new ReturnValue();

    // do some additional cleansing to handle some scenarios that are out of control with the html data
    HtmlData = HtmlData.ReplaceValue("<br>", "<br />");

    // convert html to pdf
    try
    {
        // create a stream that we can write to, in this case a MemoryStream
        using (var stream = new MemoryStream())
        {
            // create an iTextSharp Document which is an abstraction of a PDF but **NOT** a PDF
            using (var document = new Document())
            {
                // portrait vs landscape
                if (Landscape)
                {
                    document.SetPageSize(PageSize.A4.Rotate());
                }

                // create a writer that's bound to our PDF abstraction and our stream
                using (var writer = PdfWriter.GetInstance(document, stream))
                {
                    // open the document for writing
                    document.Open();

                    // read html data to StringReader
                    using (var html = new StringReader(HtmlData))
                    {
                        XMLWorkerHelper.GetInstance().ParseXHtml(writer, document, html);
                    }

                    // close document
                    document.Close();
                }
            }

            // get bytes from stream
            Result.Data = stream.ToArray();

            // success
            Result.Success = true;
        }
    }
    catch (Exception ex)
    {
        Result.Success = false;
        Result.Message = ex.Message;
    }

    // return
    return Result;
}
The ReturnValue class was simply a helper class that looks like this:

 // return value class  
 public class ReturnValue  
 {  
       // constructor  
       public ReturnValue()  
       {  
         this.Success = false;  
         this.Message = string.Empty;  
       }  
   
       // properties  
       public bool Success = false;  
       public string Message = string.Empty;  
       public Byte[] Data = null;  
 }  
We also had another method to physically create the PDF file in case you didn't want just the bytes array directly, for example:

 public static ReturnValue ConvertHtmlToPdfAsFile(string FilePath, string HtmlData)  
 {  
       // variables  
       ReturnValue Result = new ReturnValue();  
   
       try  
       {  
         // convert html to pdf and get bytes array  
         Result = ConvertHtmlToPdfAsBytes(HtmlData: HtmlData);  
   
         // check for errors  
         if (!Result.Success)  
         {  
           return Result;  
         }  
   
         // create file  
         File.WriteAllBytes(path: FilePath, bytes: Result.Data);  
   
         // result  
         Result.Success = true;  
       }  
       catch(Exception ex)  
       {  
         Result.Success = false;  
         Result.Message = ex.Message;  
       }  
   
       // return  
       return Result;  
 }  
It's important to remember that in order for this to work, you must have valid well-formed HTML; otherwise you can certainly expect for iTextSharp to throw an error. But if you have control over the HTML that you need to convert, this solution is great, and produces very nice PDF files.

It's worth noting that in our case we didn't need to pass the CSS in separately using the overloaded ParseXHtml constructor, ParseXHtml(PdfWriter writer, Document doc, Stream inp, Stream inCssFile), because we were including our CSS styles in our HTML data string instead, which for our solution was a bit cleaner.

Matt Pavey is a Microsoft Certified software developer who specializes in ASP.Net, VB.Net, C#, AJAX, LINQ, XML, XSL, Web Services, SQL, jQuery, and more. Follow on Twitter @matthewpavey

Sunday, December 11, 2016

ASP.Net C# Checking Request Header and/or Request Cookies in Global.asax Application_BeginRequest

Here is a simple example using C# to get a custom token from either the HTTP header or HTTP cookie on any page in your application. This example relies on a few custom extension methods that I regularly use, although they could be refactored out very easily.

In this particular example we're checking the Request.Headers collection first for a custom key named Token. If found we use it, if not found we check the Request.Cookies collection, and if found we use it.

Global.asax.cs
   protected void Application_BeginRequest(object sender, EventArgs e)
   {
      // variables
      string Token = string.Empty;

      // check for token in header
      if (Token.IsBlank() && Request.Headers.AllKeys.Any(k => k.IsEqual("Token")))
      {
         Token = Server.UrlDecode(Request.Headers.GetValues("Token").First());
      }

      // check for token in cookie
      if (Token.IsBlank() && Request.Cookies.AllKeys.Any(k => k.IsEqual("Token")))
      {
         Token = Server.UrlDecode(Request.Cookies.Get("Token").Value);
      }

      // if token specified try to parse it
      if (Token.HasValue())
      {
         // todo
      }

      // debug
      Response.Write("Application_BeginRequest<br />");
      Response.Write(string.Format("Token: {0}<br />", Token));
   }

The idea behind this example was to be able to let an encrypted authentication token be passed in to automatically authenticate the user for any page within the application. Having it check both the Request.Headers and the Request.Cookies collection provides some additional flexibility for the processes that pass in the token. For example, some older versions of Android code don't easily allow a custom HTTP header to be specified, but could easily set a cookie.

Matt Pavey is a Microsoft Certified software developer who specializes in ASP.Net, VB.Net, C#, AJAX, LINQ, XML, XSL, Web Services, SQL, jQuery, and more. Follow on Twitter @matthewpavey

Wednesday, April 13, 2016

ASP.Net C# Retrieving a list of videos from a YouTube playlist

Recently when working on my favorites page, as I was typing up my favorite songs and linking them to YouTube, I thought it would be pretty nice to just tap in to my "Favorites" list directly in YouTube. A quick Google search lead me to this Stack Overflow article:

http://stackoverflow.com/questions/34143202/get-all-videos-from-channel-youtube-api-v3-c-sharp

So building off of a couple of the answers in this article, I've put together a functional example using C# to show how to connect to the YouTube Data API.

For this example we'll be using the following NuGet package:

Google.Apis.YouTube.v3 Client Library

If you need to generate your own YouTube Data API key, you can visit the Google Developer Console and use the API Manager.

ASPX Page
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="default.aspx.cs" Inherits="Web.youtube._default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <!-- title -->
    <title>YouTube Demo</title>
 
    <!-- bootstrap -->
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" />
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>

    <!-- styles -->
    <style>
        body { margin: 25px !important; }
        .video { margin-top: 25px; }
        .video .title { font-weight: normal; white-space: nowrap; overflow: hidden; }
        .video .thumbnail img { width: 192px; height: 144px; }
    </style>
</head>

<body>
    <form id="form1" runat="server">
        <div class="container">
            <div class="col-lg-12">
                <h1>YouTube Demo</h1>
            </div>
            
            <!-- placeholder where we will render the results -->
            <asp:PlaceHolder ID="pnlVideos" runat="server" />

            <div class="col-lg-12" style="padding-top: 10px">
                <asp:Label ID="lblMessage" Font-Bold="true" ForeColor="Red" ClientIDMode="Static" runat="server" />
            </div>
        </div>

        <!-- template to help build each video container -->
        <asp:Literal ID="lblTemplate" Visible="false" runat="server">
            <div class="video col-lg-4">
                <div class="title">
                    <a href="{Url}" target="_blank">
                        {Title}
                    </a>
                </div>

                <div class="thumbnail">
                    <a title="{ToolTip}" href="{Url}" target="_blank">
                        <img title="{ToolTip}" src="{Image}" alt="" />
                    </a>
                </div>
            </div>
        </asp:Literal>
    </form>
</body>
</html>

Code-Behind
using Google.Apis.Services;
using Google.Apis.YouTube.v3;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace Web.youtube
{
    public partial class _default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            try
            {
                // initialize call to the youtube service
                var YouTubeService = new YouTubeService(new BaseClientService.Initializer() { ApiKey = "YourApiKey" });

                // indicate the parts we need for the request
                var ChannelListRequest = YouTubeService.Channels.List("contentDetails");

                // indicate the username for the channel you are requesting
                ChannelListRequest.ForUsername = "UserNameOfChannelYouAreRequesting";
                
                // execute the request and get the response
                var ListResponse = ChannelListRequest.Execute();

                // iterate through the results
                foreach (var channel in ListResponse.Items)
                {
                    // indicate the list you are requesting
                    // if your favorites list is unlisted you will need to explicitly set this value
                    // var ListId = channel.ContentDetails.RelatedPlaylists.Favorites;
                    var ListId = "YouTubeListId";

                    // the page token will be used if the results span multiple pages
                    var PageToken = "";

                    // iterate until there is no more data
                    while (PageToken != null)
                    {
                        // indicate the parts we need for the request
                        var PlaylistRequest = YouTubeService.PlaylistItems.List("snippet");

                        // playlist request properties
                        PlaylistRequest.PlaylistId = ListId;
                        PlaylistRequest.MaxResults = 50;
                        PlaylistRequest.PageToken = PageToken;

                        // execute the request and get the response
                        var PlaylistResponse = PlaylistRequest.Execute();

                        // iterate through the results
                        foreach (var Video in PlaylistResponse.Items)
                        {
                            // variables
                            string Template = lblTemplate.Text;
                            string VideoId = Video.Snippet.ResourceId.VideoId;
                            string Title = Video.Snippet.Title;
                            string Url = string.Format("https://www.youtube.com/watch?v={0}", VideoId);
                            string Image = Video.Snippet.Thumbnails.High.Url;

                            // replace placeholders
                            Template = Template.Replace("{VideoId}", VideoId);
                            Template = Template.Replace("{Title}", Title);
                            Template = Template.Replace("{Url}", Url);
                            Template = Template.Replace("{Image}", Image);
                            Template = Template.Replace("{ToolTip}", HttpUtility.HtmlEncode(Title));

                            // add to videos panel
                            pnlVideos.Controls.Add(new LiteralControl(Template));
                        }

                        // get the next page token
                        PageToken = PlaylistResponse.NextPageToken;
                    }
                }
            }
            catch (Exception ex)
            {
                lblMessage.Text = ex.Message;
            }
        }
    }
}

Click here to see a fully functional demo.

Matt Pavey is a Microsoft Certified software developer who specializes in ASP.Net, VB.Net, C#, AJAX, LINQ, XML, XSL, Web Services, SQL, jQuery, and more. Follow on Twitter @matthewpavey