This commit is contained in:
Tommy Parnell
2015-10-04 21:53:01 -04:00
commit a1199fe9fe
37 changed files with 1653 additions and 0 deletions

223
.gitignore vendored Normal file
View File

@@ -0,0 +1,223 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
build/
bld/
[Bb]in/
[Oo]bj/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# Windows Azure Build Output
csx/
*.build.csdef
# Windows Store app package directory
AppPackages/
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
# FAKE - F# Make
.fake/

40
DotNetMashup.sln Normal file
View File

@@ -0,0 +1,40 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{67290B97-2478-46D3-9D10-87A0B89A03C2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8610EB85-922A-40CE-AB4B-355048BFC7D2}"
ProjectSection(SolutionItems) = preProject
global.json = global.json
NuGet.Config = NuGet.Config
EndProjectSection
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "DotNetMashup", "src\DotNetMashup\DotNetMashup.xproj", "{E68542EE-79D4-47A1-BC66-BFB4B78856A1}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "DotNetMashup.Web", "src\DotNetMashup.Web\DotNetMashup.Web.xproj", "{53E3E5AF-13BF-465D-89E8-B68E4CCC4D7E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E68542EE-79D4-47A1-BC66-BFB4B78856A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E68542EE-79D4-47A1-BC66-BFB4B78856A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E68542EE-79D4-47A1-BC66-BFB4B78856A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E68542EE-79D4-47A1-BC66-BFB4B78856A1}.Release|Any CPU.Build.0 = Release|Any CPU
{53E3E5AF-13BF-465D-89E8-B68E4CCC4D7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{53E3E5AF-13BF-465D-89E8-B68E4CCC4D7E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{53E3E5AF-13BF-465D-89E8-B68E4CCC4D7E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{53E3E5AF-13BF-465D-89E8-B68E4CCC4D7E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{E68542EE-79D4-47A1-BC66-BFB4B78856A1} = {67290B97-2478-46D3-9D10-87A0B89A03C2}
{53E3E5AF-13BF-465D-89E8-B68E4CCC4D7E} = {67290B97-2478-46D3-9D10-87A0B89A03C2}
EndGlobalSection
EndGlobal

8
NuGet.Config Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<!--To inherit the global NuGet package sources remove the <clear/> line below -->
<clear />
<add key="api.nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>

6
global.json Normal file
View File

@@ -0,0 +1,6 @@
{
"projects": [ "src", "test" ],
"sdk": {
"version": "1.0.0-beta7"
}
}

View File

@@ -0,0 +1,3 @@
{
"directory": "wwwroot/lib"
}

View File

@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DotNetMashup.Web.Factories;
using Microsoft.AspNet.Mvc;
namespace DotNetMashup.Web.Controllers
{
public class HomeController : Controller
{
private readonly BlogPostFactory factory;
public HomeController(BlogPostFactory factory)
{
this.factory = factory;
}
public IActionResult Index()
{
var data = factory.GetData();
return View();
}
public IActionResult About()
{
ViewData["Message"] = "Your application description page.";
return View();
}
public IActionResult Contact()
{
ViewData["Message"] = "Your contact page.";
return View();
}
public IActionResult Error()
{
return View("~/Views/Shared/Error.cshtml");
}
}
}

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>53e3e5af-13bf-465d-89e8-b68e4ccc4d7e</ProjectGuid>
<RootNamespace>DotNetMashup.Web</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
<DevelopmentServerPort>59713</DevelopmentServerPort>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@@ -0,0 +1,169 @@
//This code came from https://raw.githubusercontent.com/robvolk/Helpers.Net/master/Src/Helpers.Net/StringHtmlExtensions.cs
namespace DotNetMashup.Web.Extensions
{
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
public static class StringHtmlExtensions
{
/// <summary>
/// Truncates a string containing HTML to a number of text characters, keeping whole words.
/// The result contains HTML and any tags left open are closed.
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static string TruncateHtml(this string html, int maxCharacters, string trailingText)
{
if(string.IsNullOrEmpty(html))
return html;
// find the spot to truncate
// count the text characters and ignore tags
var textCount = 0;
var charCount = 0;
var ignore = false;
foreach(char c in html)
{
charCount++;
if(c == '<')
ignore = true;
else if(!ignore)
textCount++;
if(c == '>')
ignore = false;
// stop once we hit the limit
if(textCount >= maxCharacters)
break;
}
// Truncate the html and keep whole words only
var trunc = new StringBuilder(html.TruncateWords(charCount));
// keep track of open tags and close any tags left open
var tags = new Stack<string>();
var matches = Regex.Matches(trunc.ToString(),
@"<((?<tag>[^\s/>]+)|/(?<closeTag>[^\s>]+)).*?(?<selfClose>/)?\s*>",
RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Multiline);
foreach(Match match in matches)
{
if(match.Success)
{
var tag = match.Groups["tag"].Value;
var closeTag = match.Groups["closeTag"].Value;
// push to stack if open tag and ignore it if it is self-closing, i.e. <br />
if(!string.IsNullOrEmpty(tag) && string.IsNullOrEmpty(match.Groups["selfClose"].Value))
tags.Push(tag);
// pop from stack if close tag
else if(!string.IsNullOrEmpty(closeTag))
{
// pop the tag to close it.. find the matching opening tag
// ignore any unclosed tags
while(tags.Pop() != closeTag && tags.Count > 0)
{ }
}
}
}
if(html.Length > charCount)
// add the trailing text
trunc.Append(trailingText);
// pop the rest off the stack to close remainder of tags
while(tags.Count > 0)
{
trunc.Append("</");
trunc.Append(tags.Pop());
trunc.Append('>');
}
return trunc.ToString();
}
/// <summary>
/// Truncates a string containing HTML to a number of text characters, keeping whole words.
/// The result contains HTML and any tags left open are closed.
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static string TruncateHtml(this string html, int maxCharacters)
{
return html.TruncateHtml(maxCharacters, null);
}
/// <summary>
/// Strips all HTML tags from a string
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static string StripHtml(this string html)
{
if(string.IsNullOrEmpty(html))
return html;
return Regex.Replace(html, @"<(.|\n)*?>", string.Empty);
}
/// <summary>
/// Truncates text to a number of characters
/// </summary>
/// <param name="text"></param>
/// <param name="maxCharacters"></param>
/// <param name="trailingText"></param>
/// <returns></returns>
public static string Truncate(this string text, int maxCharacters)
{
return text.Truncate(maxCharacters, null);
}
/// <summary>
/// Truncates text to a number of characters and adds trailing text, i.e. elipses, to the end
/// </summary>
/// <param name="text"></param>
/// <param name="maxCharacters"></param>
/// <param name="trailingText"></param>
/// <returns></returns>
public static string Truncate(this string text, int maxCharacters, string trailingText)
{
if(string.IsNullOrEmpty(text) || maxCharacters <= 0 || text.Length <= maxCharacters)
return text;
else
return text.Substring(0, maxCharacters) + trailingText;
}
/// <summary>
/// Truncates text and discars any partial words left at the end
/// </summary>
/// <param name="text"></param>
/// <param name="maxCharacters"></param>
/// <param name="trailingText"></param>
/// <returns></returns>
public static string TruncateWords(this string text, int maxCharacters)
{
return text.TruncateWords(maxCharacters, null);
}
/// <summary>
/// Truncates text and discars any partial words left at the end
/// </summary>
/// <param name="text"></param>
/// <param name="maxCharacters"></param>
/// <param name="trailingText"></param>
/// <returns></returns>
public static string TruncateWords(this string text, int maxCharacters, string trailingText)
{
if(string.IsNullOrEmpty(text) || maxCharacters <= 0 || text.Length <= maxCharacters)
return text;
// trunctate the text, then remove the partial word at the end
return Regex.Replace(text.Truncate(maxCharacters),
@"\s+[^\s]+$", string.Empty, RegexOptions.IgnoreCase | RegexOptions.Compiled) + trailingText;
}
}
}

View File

@@ -0,0 +1,151 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.ServiceModel.Syndication;
using System.Threading.Tasks;
using System.Xml;
using DotNetMashup.Web.Extensions;
using DotNetMashup.Web.Global;
using DotNetMashup.Web.Model;
using Microsoft.Framework.Caching.Memory;
namespace DotNetMashup.Web.Factories
{
public class BlogPostFactory : IFactory
{
private readonly ISiteSetting setting;
private readonly IMemoryCache cache;
private readonly IEnumerable<MetaData> _data;
private const string cacheKey = "blogposts";
public BlogPostFactory(IEnumerable<MetaData> data, IMemoryCache cache, ISiteSetting setting)
{
this._data = data;
this.cache = cache;
this.setting = setting;
}
public string FactoryName
{
get
{
return "BlogPost";
}
}
public IEnumerable<IExternalData> GetData()
{
var cachedata = cache.Get<IEnumerable<IExternalData>>(cacheKey);
if(cachedata != null) return cachedata;
var syndicationFeeds = GetSyndicationFeeds(_data);
var data = syndicationFeeds
.SelectMany(pair => pair.Value.Items, (pair, item) => new { Id = pair.Key, Item = item })
.Where(x => x.Item.Categories.Any(category => setting.Categories.Any(setting => string.Equals(setting, category.Name, StringComparison.OrdinalIgnoreCase))))
.Select(x =>
{
var metaauthor = _data.First(y => y.Id == x.Id);
var authorname = metaauthor.Author;
var authoremail = metaauthor.AuthorEmail;
var link = x.Item.Links.FirstOrDefault(y => y.RelationshipType == "alternate");
var locallink = string.Empty;
if(link != null)
{
locallink = link.Uri.Segments.Last();
if(locallink.Contains("."))
{
locallink = locallink.Substring(0, locallink.IndexOf(".", System.StringComparison.Ordinal));
}
}
var originallink = link == null ? string.Empty : link.Uri.AbsoluteUri;
var summary = x.Item.Summary == null
? ((TextSyndicationContent)x.Item.Content).Text
: x.Item.Summary.Text;
var truncatedSummary = summary.TruncateHtml(700, "");
var encodedcontent = x.Item.ElementExtensions.ReadElementExtensions<string>("encoded",
"http://purl.org/rss/1.0/modules/content/");
var content = string.Empty;
if(encodedcontent.Any())
{
content = encodedcontent.First();
}
else if(x.Item.Content != null)
{
content = ((TextSyndicationContent)x.Item.Content).Text;
}
else
{
content = summary;
}
return new BlogPost
{
Title = x.Item.Title.Text,
Summary = truncatedSummary,
Author = authorname,
AuthorEmail = authoremail,
Localink = locallink,
OriginalLink = originallink,
PublishedDate = x.Item.PublishDate.DateTime,
Content = content
};
})
.OrderByDescending(x => x.PublishedDate)
.ToList();
cache.Set(cacheKey, data.Cast<IExternalData>());
return data;
}
private static IEnumerable<KeyValuePair<string, SyndicationFeed>> GetSyndicationFeeds(IEnumerable<MetaData> metadataEntries)
{
var syndicationFeeds = new List<KeyValuePair<string, SyndicationFeed>>();
foreach(var metadata in metadataEntries)
{
GetFeed(metadata.FeedUrl, metadata.Id, syndicationFeeds);
}
return syndicationFeeds;
}
private static void GetFeed(string url, string id, List<KeyValuePair<string, SyndicationFeed>> syndicationFeeds)
{
try
{
SyndicationFeed feed = null;
using(var reader = XmlReader.Create(url))
{
feed = SyndicationFeed.Load(reader);
}
if(feed != null)
{
syndicationFeeds.Add(new KeyValuePair<string, SyndicationFeed>(id, feed));
if(feed.Links.Any(x => x.RelationshipType == "next"))
{
foreach(var pagingLink in feed.Links.Where(x => x.RelationshipType == "next"))
{
GetFeed(pagingLink.Uri.AbsoluteUri, id, syndicationFeeds);
}
}
}
}
catch(WebException)
{
//Unable to load RSS feed
}
catch(XmlException)
{
//Unable to load RSS feed
}
}
}
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DotNetMashup.Web.Model;
namespace DotNetMashup.Web.Factories
{
public interface IFactory
{
string FactoryName { get; }
IEnumerable<IExternalData> GetData();
}
}

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace DotNetMashup.Web.Global
{
public interface ISiteSetting
{
List<string> Categories { get; }
}
}

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace DotNetMashup.Web.Global
{
public class SiteSettings : ISiteSetting
{
public List<string> Categories { get; } = new List<string> { "c#", "csharp", "cs", "asp.net", "NancyFx", "Nancy", "vNext", "asp.net 5" };
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace DotNetMashup.Web.Model
{
public class BlogPost : IExternalData
{
public string Title { get; set; }
public string Content { get; set; }
public DateTime PublishedDate { get; set; }
public string Summary { get; set; }
public string Localink { get; set; }
public string OriginalLink { get; set; }
public string Author { get; set; }
public string AuthorEmail { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace DotNetMashup.Web.Model
{
public interface IExternalData
{
string Title { get; set; }
string Content { get; set; }
string OriginalLink { get; set; }
string Author { get; set; }
}
}

View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace DotNetMashup.Web.Model
{
public interface IFeedData
{
string FeedUrl { get; set; }
string Author { get; set; }
string AuthorEmail { get; set; }
string GravatarUrl { get; set; }
string Id { get; set; }
}
}

View File

@@ -0,0 +1,12 @@
namespace DotNetMashup.Web.Model
{
//stolen idea from: https://github.com/NancyFx/Nancy.Blog/blob/master/src/Nancy.Blog/Model/MetaData.cs
public class MetaData : IFeedData
{
public string FeedUrl { get; set; }
public string Author { get; set; }
public string AuthorEmail { get; set; }
public string GravatarUrl { get; set; }
public string Id { get; set; }
}
}

View File

@@ -0,0 +1,203 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Welcome to ASP.NET 5</title>
<style>
html {
background: #f1f1f1;
height: 100%;
}
body {
background: #fff;
color: #505050;
font: 14px 'Segoe UI', tahoma, arial, helvetica, sans-serif;
margin: 1%;
min-height: 95.5%;
border: 1px solid silver;
position: relative;
}
#header {
padding: 0;
}
#header h1 {
font-size: 44px;
font-weight: normal;
margin: 0;
padding: 10px 30px 10px 30px;
}
#header span {
margin: 0;
padding: 0 30px;
display: block;
}
#header p {
font-size: 20px;
color: #fff;
background: #007acc;
padding: 0 30px;
line-height: 50px;
margin-top: 25px;
}
#header p a {
color: #fff;
text-decoration: underline;
font-weight: bold;
padding-right: 35px;
background: no-repeat right bottom url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAAWCAMAAAAcqPc3AAAANlBMVEUAAAAAeswfitI9mthXp91us+KCvuaTx+mjz+2x1u+83PLH4vTR5/ba7Pjj8Pns9fv1+v3////wy3dWAAAAAXRSTlMAQObYZgAAAHxJREFUeNp9kVcSwCAIRMHUYoH7XzaxOxJ9P8oyQ1uIqNPwh3s2aLmIM2YtqrLcQIeQEylhuCeUOlhgve5yoBCfWmlnlgkN4H8ykbpaE7gR03AbUHiwoOxUH9Xp+ubd41p1HF3mBPrfC87BHeTdaB3ceeKL9HGpcvX9zu6+DdMWT9KQPvYAAAAASUVORK5CYII=);
}
#main {
padding: 5px 30px;
clear: both;
}
.section {
width: 21.7%;
float: left;
margin: 0 0 0 4%;
}
.section h2 {
font-size: 13px;
text-transform: uppercase;
margin: 0;
border-bottom: 1px solid silver;
padding-bottom: 12px;
margin-bottom: 8px;
}
.section.first {
margin-left: 0;
}
.section.first h2 {
font-size: 24px;
text-transform: none;
margin-bottom: 25px;
border: none;
}
.section.first li {
border-top: 1px solid silver;
padding: 8px 0;
}
.section.last {
margin-right: 0;
}
ul {
list-style: none;
padding: 0;
margin: 0;
line-height: 20px;
}
li {
padding: 4px 0;
}
a {
color: #267cb2;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
#footer {
clear: both;
padding-top: 50px;
}
#footer p {
position: absolute;
bottom: 10px;
}
</style>
</head>
<body>
<div id="header">
<h1>Welcome to ASP.NET 5 Preview</h1>
<span>
We've made some big updates in this release, so its <b>important</b> that you spend
a few minutes to learn whats new.
<br /><br />
ASP.NET 5 has been rearchitected to make it <b>lean</b> and <b>composable</b>. It's fully
<b>open source</b> and available on <a href="http://go.microsoft.com/fwlink/?LinkID=517854">GitHub</a>.
<br />
Your new project automatically takes advantage of modern client-side utilities
like <a href="http://go.microsoft.com/fwlink/?LinkId=518004">Bower</a> and <a href="http://go.microsoft.com/fwlink/?LinkId=518005">npm</a>
(to add client-side libraries) and <a href="http://go.microsoft.com/fwlink/?LinkId=518007">Gulp</a> (for client-side build and automation tasks).
<br /><br />
We hope you enjoy the new capabilities in ASP.NET 5 and Visual Studio 2015.
<br />
The ASP.NET Team
</span>
<p>You've created a new ASP.NET 5 project. <a href="http://go.microsoft.com/fwlink/?LinkId=518016">Learn what's new</a></p>
</div>
<div id="main">
<div class="section first">
<h2>This application consists of:</h2>
<ul>
<li>Sample pages using ASP.NET MVC 6</li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=518007">Gulp</a> and <a href="http://go.microsoft.com/fwlink/?LinkId=518004">Bower</a> for managing client-side resources</li>
<li>Theming using <a href="http://go.microsoft.com/fwlink/?LinkID=398939">Bootstrap</a></li>
</ul>
</div>
<div class="section">
<h2>New concepts</h2>
<ul>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=518008">The 'wwwroot' explained</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=518012">Configuration in ASP.NET 5</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=518013">Dependency Injection</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=518014">Razor TagHelpers</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=517849">Manage client tasks using Gulp</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=517850">Develop on different platforms</a></li>
</ul>
</div>
<div class="section">
<h2>Customize app</h2>
<ul>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=398600">Add Controllers and Views</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=398602">Add Data using EntityFramework</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=398603">Add Authentication using Identity</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=398606">Add real time support using SignalR</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=398604">Add Class library</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=518009">Add Web APIs with MVC 6</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=517848">Add client packages using Bower</a></li>
</ul>
</div>
<div class="section last">
<h2>Deploy</h2>
<ul>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=517851">Run your app locally</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=517852">Run your app on ASP.NET Core 5</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=517853">Run commands in your project.json</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=398609">Publish to Microsoft Azure Web Sites</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=518019">Publish to the file system</a></li>
</ul>
</div>
<div id="footer">
<p>We would love to hear your <a href="http://go.microsoft.com/fwlink/?LinkId=518015">feedback</a></p>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,91 @@
using System.Collections.Generic;
using System.IO;
using DotNetMashup.Web.Factories;
using DotNetMashup.Web.Global;
using DotNetMashup.Web.Model;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.Dnx.Runtime;
using Microsoft.Framework.Caching.Memory;
using Microsoft.Framework.Configuration;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Logging;
using Newtonsoft.Json;
namespace DotNetMashup.Web
{
public class Startup
{
private IEnumerable<MetaData> _feedData = null;
public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
{
// Setup configuration sources.
var builder = new ConfigurationBuilder(appEnv.ApplicationBasePath)
.AddJsonFile("config.json")
.AddEnvironmentVariables();
Configuration = builder.Build();
_feedData = JsonConvert.DeserializeObject<IEnumerable<MetaData>>(File.ReadAllText(Path.Combine(appEnv.ApplicationBasePath, "blogfeed.json")));
}
public IConfigurationRoot Configuration { get; set; }
// This method gets called by the runtime.
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<ISiteSetting>(prov =>
{
return new SiteSettings();
});
services.AddSingleton<IMemoryCache>((provider) =>
{
return new MemoryCache(new MemoryCacheOptions());
});
services.AddInstance(_feedData);
services.AddSingleton<BlogPostFactory>();
// Add MVC services to the services container.
services.AddMvc();
// Uncomment the following line to add Web API services which makes it easier to port Web API 2 controllers.
// You will also need to add the Microsoft.AspNet.Mvc.WebApiCompatShim package to the 'dependencies' section of project.json.
// services.AddWebApiConventions();
}
// Configure is called after ConfigureServices is called.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.MinimumLevel = LogLevel.Information;
loggerFactory.AddConsole();
loggerFactory.AddDebug();
// Configure the HTTP request pipeline.
// Add the following to the request pipeline only in development environment.
if(env.IsDevelopment())
{
app.UseBrowserLink();
app.UseErrorPage();
}
else
{
// Add Error handling middleware which catches all application specific errors and
// send the request to the following path or controller action.
app.UseErrorHandler("/Home/Error");
}
// Add static files to the request pipeline.
app.UseStaticFiles();
// Add MVC to the request pipeline.
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
// Uncomment the following line to add a route for porting Web API 2 controllers.
// routes.MapWebApiRoute("DefaultApi", "api/{controller}/{id?}");
});
}
}
}

View File

@@ -0,0 +1,7 @@
@{
ViewData["Title"] = "About";
}
<h2>@ViewData["Title"].</h2>
<h3>@ViewData["Message"]</h3>
<p>Use this area to provide additional information.</p>

View File

@@ -0,0 +1,17 @@
@{
ViewData["Title"] = "Contact";
}
<h2>@ViewData["Title"].</h2>
<h3>@ViewData["Message"]</h3>
<address>
One Microsoft Way<br />
Redmond, WA 98052-6399<br />
<abbr title="Phone">P:</abbr>
425.555.0100
</address>
<address>
<strong>Support:</strong> <a href="mailto:Support@example.com">Support@example.com</a><br />
<strong>Marketing:</strong> <a href="mailto:Marketing@example.com">Marketing@example.com</a>
</address>

View File

@@ -0,0 +1,104 @@
@{
ViewData["Title"] = "Home Page";
}
<div id="myCarousel" class="carousel slide" data-ride="carousel" data-interval="6000">
<ol class="carousel-indicators">
<li data-target="#myCarousel" data-slide-to="0" class="active"></li>
<li data-target="#myCarousel" data-slide-to="1"></li>
<li data-target="#myCarousel" data-slide-to="2"></li>
<li data-target="#myCarousel" data-slide-to="3"></li>
</ol>
<div class="carousel-inner" role="listbox">
<div class="item active">
<img src="~/images/ASP-NET-Banners-01.png" alt="ASP.NET" class="img-responsive" />
<div class="container">
<div class="carousel-caption">
<p>
Learn how to build ASP.NET apps that can run anywhere.
<a class="btn btn-default btn-default" href="http://go.microsoft.com/fwlink/?LinkID=525028&clcid=0x409">
Learn More
</a>
</p>
</div>
</div>
</div>
<div class="item">
<img src="~/images/Banner-02-VS.png" alt="Visual Studio" class="img-responsive" />
<div class="container">
<div class="carousel-caption">
<p>
There are powerful new features in Visual Studio for building modern web apps.
<a class="btn btn-default btn-default" href="http://go.microsoft.com/fwlink/?LinkID=525030&clcid=0x409">
Learn More
</a>
</p>
</div>
</div>
</div>
<div class="item">
<img src="~/images/ASP-NET-Banners-02.png" alt="Package Management" class="img-responsive" />
<div class="container">
<div class="carousel-caption">
<p>
Bring in libraries from NuGet, Bower, and npm, and automate tasks using Grunt or Gulp.
<a class="btn btn-default btn-default" href="http://go.microsoft.com/fwlink/?LinkID=525029&clcid=0x409">
Learn More
</a>
</p>
</div>
</div>
</div>
<div class="item">
<img src="~/images/Banner-01-Azure.png" alt="Microsoft Azure" class="img-responsive" />
<div class="container">
<div class="carousel-caption">
<p>
Learn how Microsoft's Azure cloud platform allows you to build, deploy, and scale web apps.
<a class="btn btn-default btn-default" href="http://go.microsoft.com/fwlink/?LinkID=525027&clcid=0x409">
Learn More
</a>
</p>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-3">
<h2>Application uses</h2>
<ul>
<li>Sample pages using ASP.NET 5 (MVC 6)</li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=518007">Gulp</a> and <a href="http://go.microsoft.com/fwlink/?LinkId=518004">Bower</a> for managing client-side resources</li>
<li>Theming using <a href="http://go.microsoft.com/fwlink/?LinkID=398939">Bootstrap</a></li>
</ul>
</div>
<div class="col-md-3">
<h2>New concepts</h2>
<ul>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=518008">Conceptual overview of ASP.NET 5</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=518008">Fundamentals in ASP.NET 5</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=517849">Client-Side Development using npm, Bower and Gulp</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=517850">Develop on different platforms</a></li>
</ul>
</div>
<div class="col-md-3">
<h2>Customize app</h2>
<ul>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=398600">Add Controllers and Views</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=398602">Add Data using EntityFramework</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=398603">Add Authentication using Identity</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=517848">Manage client-side packages using Bower/ Gulp</a></li>
</ul>
</div>
<div class="col-md-3">
<h2>Deploy</h2>
<ul>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=517851">Run your app locally</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=517852">Run your app on .NET Core</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=517853">Run commands in your app</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=398609">Publish to Microsoft Azure Web Apps</a></li>
</ul>
</div>
</div>

View File

@@ -0,0 +1,6 @@
@{
ViewData["Title"] = "Error";
}
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>

View File

@@ -0,0 +1,80 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - DotNetMashup.Web</title>
<environment names="Development">
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/lib/bootstrap-touch-carousel/dist/css/bootstrap-touch-carousel.css" />
<link rel="stylesheet" href="~/css/site.css" />
</environment>
<environment names="Staging,Production">
<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.0.0/css/bootstrap.min.css"
asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
asp-fallback-test-class="hidden" asp-fallback-test-property="visibility" asp-fallback-test-value="hidden" />
<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap-touch-carousel/0.8.0/css/bootstrap-touch-carousel.css"
asp-fallback-href="~/lib/bootstrap-touch-carousel/css/bootstrap-touch-carousel.css"
asp-fallback-test-class="carousel-caption" asp-fallback-test-property="display" asp-fallback-test-value="none" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
</environment>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a asp-controller="Home" asp-action="Index" class="navbar-brand">DotNetMashup.Web</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a asp-controller="Home" asp-action="Index">Home</a></li>
<li><a asp-controller="Home" asp-action="About">About</a></li>
<li><a asp-controller="Home" asp-action="Contact">Contact</a></li>
</ul>
</div>
</div>
</div>
<div class="container body-content">
@RenderBody()
<hr />
<footer>
<p>&copy; 2015 - DotNetMashup.Web</p>
</footer>
</div>
<environment names="Development">
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
<script src="~/lib/hammer.js/hammer.js"></script>
<script src="~/lib/bootstrap-touch-carousel/dist/js/bootstrap-touch-carousel.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
</environment>
<environment names="Staging,Production">
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.1.4.min.js"
asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
asp-fallback-test="window.jQuery">
</script>
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.0.0/bootstrap.min.js"
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal">
</script>
<script src="https://ajax.aspnetcdn.com/ajax/hammer.js/2.0.4/hammer.min.js"
asp-fallback-src="~/lib/hammer.js/hammer.js"
asp-fallback-test="window.Hammer">
</script>
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap-touch-carousel/0.8.0/js/bootstrap-touch-carousel.js"
asp-fallback-src="~/lib/bootstrap-touch-carousel/dist/js/bootstrap-touch-carousel.js"
asp-fallback-test="window.Hammer && window.Hammer.Instance">
</script>
<script src="~/js/site.js" asp-append-version="true"></script>
</environment>
@RenderSection("scripts", required: false)
</body>
</html>

View File

@@ -0,0 +1,2 @@
@using DotNetMashup.Web
@addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers"

View File

@@ -0,0 +1,3 @@
@{
Layout = "_Layout";
}

View File

@@ -0,0 +1,9 @@
[
{
"id": "tparnell",
"feedurl": "https://blog.tommyparnell.com/rss/",
"author": "Tommy Parnell",
"authoremail": "tparnell8@gmail.com",
"gravatarurl": "http://www.gravatar.com/avatar/333e3cea32cd17ff2007d131df336061.png?s=128"
}
]

View File

@@ -0,0 +1,12 @@
{
"name": "ASP.NET",
"private": true,
"dependencies": {
"bootstrap": "3.0.0",
"bootstrap-touch-carousel": "0.8.0",
"hammer.js": "2.0.4",
"jquery": "2.1.4",
"jquery-validation": "1.11.1",
"jquery-validation-unobtrusive": "3.2.2"
}
}

View File

@@ -0,0 +1,7 @@
{
"Data": {
"DefaultConnection": {
"ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=DotNetMashup;Trusted_Connection=True;MultipleActiveResultSets=true"
}
}
}

View File

@@ -0,0 +1,45 @@
/// <binding Clean='clean' />
var gulp = require("gulp"),
rimraf = require("rimraf"),
concat = require("gulp-concat"),
cssmin = require("gulp-cssmin"),
uglify = require("gulp-uglify"),
project = require("./project.json");
var paths = {
webroot: "./" + project.webroot + "/"
};
paths.js = paths.webroot + "js/**/*.js";
paths.minJs = paths.webroot + "js/**/*.min.js";
paths.css = paths.webroot + "css/**/*.css";
paths.minCss = paths.webroot + "css/**/*.min.css";
paths.concatJsDest = paths.webroot + "js/site.min.js";
paths.concatCssDest = paths.webroot + "css/site.min.css";
gulp.task("clean:js", function (cb) {
rimraf(paths.concatJsDest, cb);
});
gulp.task("clean:css", function (cb) {
rimraf(paths.concatCssDest, cb);
});
gulp.task("clean", ["clean:js", "clean:css"]);
gulp.task("min:js", function () {
gulp.src([paths.js, "!" + paths.minJs], { base: "." })
.pipe(concat(paths.concatJsDest))
.pipe(uglify())
.pipe(gulp.dest("."));
});
gulp.task("min:css", function () {
gulp.src([paths.css, "!" + paths.minCss])
.pipe(concat(paths.concatCssDest))
.pipe(cssmin())
.pipe(gulp.dest("."));
});
gulp.task("min", ["min:js", "min:css"]);

View File

@@ -0,0 +1,2 @@
server=Microsoft.AspNet.Server.WebListener
server.urls=http://localhost:5000

View File

@@ -0,0 +1,11 @@
{
"name": "ASP.NET",
"version": "0.0.0",
"devDependencies": {
"gulp": "3.8.11",
"gulp-concat": "2.5.2",
"gulp-cssmin": "0.1.7",
"gulp-uglify": "1.2.0",
"rimraf": "2.2.8"
}
}

View File

@@ -0,0 +1,48 @@
{
"webroot": "wwwroot",
"version": "1.0.0-*",
"dependencies": {
"Microsoft.AspNet.Diagnostics": "1.0.0-beta7",
"Microsoft.AspNet.Mvc": "6.0.0-beta7",
"Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-beta7",
"Microsoft.AspNet.Server.IIS": "1.0.0-beta7",
"Microsoft.AspNet.Server.WebListener": "1.0.0-beta7",
"Microsoft.AspNet.StaticFiles": "1.0.0-beta7",
"Microsoft.AspNet.Tooling.Razor": "1.0.0-beta7",
"Microsoft.Framework.Configuration.Json": "1.0.0-beta7",
"Microsoft.Framework.Logging": "1.0.0-beta7",
"Microsoft.Framework.Logging.Console": "1.0.0-beta7",
"Microsoft.Framework.Logging.Debug": "1.0.0-beta7",
"Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0-beta7",
"Newtonsoft.Json": "7.0.1"
},
"commands": {
"web": "Microsoft.AspNet.Hosting --config hosting.ini"
},
"frameworks": {
"dnx451": {
"frameworkAssemblies": {
"System.ServiceModel": "4.0.0.0"
}
}
},
"exclude": [
"wwwroot",
"node_modules",
"bower_components"
],
"publishExclude": [
"node_modules",
"bower_components",
"**.xproj",
"**.user",
"**.vspscc"
],
"scripts": {
"prepublish": [ "npm install", "bower install", "gulp clean", "gulp min" ]
}
}

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>e68542ee-79d4-47a1-bc66-bfb4b78856a1</ProjectGuid>
<RootNamespace>DotNetMashup</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@@ -0,0 +1,169 @@
//This code came from https://raw.githubusercontent.com/robvolk/Helpers.Net/master/Src/Helpers.Net/StringHtmlExtensions.cs
namespace DotNetMashup.Extensions
{
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
public static class StringHtmlExtensions
{
/// <summary>
/// Truncates a string containing HTML to a number of text characters, keeping whole words.
/// The result contains HTML and any tags left open are closed.
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static string TruncateHtml(this string html, int maxCharacters, string trailingText)
{
if(string.IsNullOrEmpty(html))
return html;
// find the spot to truncate
// count the text characters and ignore tags
var textCount = 0;
var charCount = 0;
var ignore = false;
foreach(char c in html)
{
charCount++;
if(c == '<')
ignore = true;
else if(!ignore)
textCount++;
if(c == '>')
ignore = false;
// stop once we hit the limit
if(textCount >= maxCharacters)
break;
}
// Truncate the html and keep whole words only
var trunc = new StringBuilder(html.TruncateWords(charCount));
// keep track of open tags and close any tags left open
var tags = new Stack<string>();
var matches = Regex.Matches(trunc.ToString(),
@"<((?<tag>[^\s/>]+)|/(?<closeTag>[^\s>]+)).*?(?<selfClose>/)?\s*>",
RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Multiline);
foreach(Match match in matches)
{
if(match.Success)
{
var tag = match.Groups["tag"].Value;
var closeTag = match.Groups["closeTag"].Value;
// push to stack if open tag and ignore it if it is self-closing, i.e. <br />
if(!string.IsNullOrEmpty(tag) && string.IsNullOrEmpty(match.Groups["selfClose"].Value))
tags.Push(tag);
// pop from stack if close tag
else if(!string.IsNullOrEmpty(closeTag))
{
// pop the tag to close it.. find the matching opening tag
// ignore any unclosed tags
while(tags.Pop() != closeTag && tags.Count > 0)
{ }
}
}
}
if(html.Length > charCount)
// add the trailing text
trunc.Append(trailingText);
// pop the rest off the stack to close remainder of tags
while(tags.Count > 0)
{
trunc.Append("</");
trunc.Append(tags.Pop());
trunc.Append('>');
}
return trunc.ToString();
}
/// <summary>
/// Truncates a string containing HTML to a number of text characters, keeping whole words.
/// The result contains HTML and any tags left open are closed.
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static string TruncateHtml(this string html, int maxCharacters)
{
return html.TruncateHtml(maxCharacters, null);
}
/// <summary>
/// Strips all HTML tags from a string
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static string StripHtml(this string html)
{
if(string.IsNullOrEmpty(html))
return html;
return Regex.Replace(html, @"<(.|\n)*?>", string.Empty);
}
/// <summary>
/// Truncates text to a number of characters
/// </summary>
/// <param name="text"></param>
/// <param name="maxCharacters"></param>
/// <param name="trailingText"></param>
/// <returns></returns>
public static string Truncate(this string text, int maxCharacters)
{
return text.Truncate(maxCharacters, null);
}
/// <summary>
/// Truncates text to a number of characters and adds trailing text, i.e. elipses, to the end
/// </summary>
/// <param name="text"></param>
/// <param name="maxCharacters"></param>
/// <param name="trailingText"></param>
/// <returns></returns>
public static string Truncate(this string text, int maxCharacters, string trailingText)
{
if(string.IsNullOrEmpty(text) || maxCharacters <= 0 || text.Length <= maxCharacters)
return text;
else
return text.Substring(0, maxCharacters) + trailingText;
}
/// <summary>
/// Truncates text and discars any partial words left at the end
/// </summary>
/// <param name="text"></param>
/// <param name="maxCharacters"></param>
/// <param name="trailingText"></param>
/// <returns></returns>
public static string TruncateWords(this string text, int maxCharacters)
{
return text.TruncateWords(maxCharacters, null);
}
/// <summary>
/// Truncates text and discars any partial words left at the end
/// </summary>
/// <param name="text"></param>
/// <param name="maxCharacters"></param>
/// <param name="trailingText"></param>
/// <returns></returns>
public static string TruncateWords(this string text, int maxCharacters, string trailingText)
{
if(string.IsNullOrEmpty(text) || maxCharacters <= 0 || text.Length <= maxCharacters)
return text;
// trunctate the text, then remove the partial word at the end
return Regex.Replace(text.Truncate(maxCharacters),
@"\s+[^\s]+$", string.Empty, RegexOptions.IgnoreCase | RegexOptions.Compiled) + trailingText;
}
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace DotNetMashup.Model
{
public class BlogPost
{
public string Title { get; set; }
public string Content { get; set; }
public DateTime PublishedDate { get; set; }
public string Summary { get; set; }
public string Localink { get; set; }
public string OriginalLink { get; set; }
public string Author { get; set; }
public string AuthorEmail { get; set; }
}
}

View File

@@ -0,0 +1,12 @@
namespace DotNetMashup
{
//stolen idea from: https://github.com/NancyFx/Nancy.Blog/blob/master/src/Nancy.Blog/Model/MetaData.cs
public class MetaData
{
public string FeedUrl { get; set; }
public string Author { get; set; }
public string AuthorEmail { get; set; }
public string GravatarUrl { get; set; }
public string Id { get; set; }
}
}

View File

@@ -0,0 +1,22 @@
{
"version": "1.0.0-*",
"description": "DotNetMashup Class Library",
"authors": [ "Tommy Parnell" ],
"tags": [ "" ],
"projectUrl": "",
"licenseUrl": "",
"frameworks": {
"dnx451": { },
"dnxcore50": {
"dependencies": {
"Microsoft.CSharp": "4.0.1-beta-23225",
"System.Collections": "4.0.11-beta-23225",
"System.Linq": "4.0.1-beta-23225",
"System.Runtime": "4.0.21-beta-23225",
"System.Threading": "4.0.11-beta-23225",
"System.Text.RegularExpressions": "4.0.11-beta-23225"
}
}
}
}