Skip to content

Commit

Permalink
Merge pull request #197 from JoeMayo/blazor-server-side
Browse files Browse the repository at this point in the history
Blazor server side
  • Loading branch information
ADefWebserver authored Jun 22, 2020
2 parents 4f9222c + 593bf61 commit 3c58f49
Show file tree
Hide file tree
Showing 33 changed files with 1,631 additions and 2 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -258,4 +258,5 @@ paket-files/

# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
*.pyc
/Samples/LinqToTwitter5/net48/CSharp/AspNetSamples/MvcDemo
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29926.136
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoreDemo", "CoreDemo\CoreDemo.csproj", "{589AD110-3424-48E3-88EA-5E39BF1141B0}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoreDemo", "CoreDemo\CoreDemo.csproj", "{589AD110-3424-48E3-88EA-5E39BF1141B0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MvcDemo", "MvcDemo\MvcDemo.csproj", "{80E20BC0-3F39-4DB8-AB7A-571DEC8DC875}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorDemo", "BlazorDemo\BlazorDemo.csproj", "{32C830C6-5275-4E9E-AAFA-9AD26E57FC20}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -21,6 +23,10 @@ Global
{80E20BC0-3F39-4DB8-AB7A-571DEC8DC875}.Debug|Any CPU.Build.0 = Debug|Any CPU
{80E20BC0-3F39-4DB8-AB7A-571DEC8DC875}.Release|Any CPU.ActiveCfg = Release|Any CPU
{80E20BC0-3F39-4DB8-AB7A-571DEC8DC875}.Release|Any CPU.Build.0 = Release|Any CPU
{32C830C6-5275-4E9E-AAFA-9AD26E57FC20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{32C830C6-5275-4E9E-AAFA-9AD26E57FC20}.Debug|Any CPU.Build.0 = Debug|Any CPU
{32C830C6-5275-4E9E-AAFA-9AD26E57FC20}.Release|Any CPU.ActiveCfg = Release|Any CPU
{32C830C6-5275-4E9E-AAFA-9AD26E57FC20}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Blazored.SessionStorage" Version="1.0.12" />
<PackageReference Include="linqtotwitter" Version="5.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
<PackageReference Include="Microsoft.AspNetCore.Session" Version="2.2.0" />
<PackageReference Include="System.Text.Json" Version="4.7.2" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.WebUtilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace BlazorDemo.Classes
{
// From: Working with Query Strings in Blazor
// https://chrissainty.com/working-with-query-strings-in-blazor/
public static class NavigationManagerExtensions
{
public static bool TryGetQueryString<T>(this NavigationManager navManager, string key, out T value)
{
var uri = navManager.ToAbsoluteUri(navManager.Uri);

if (QueryHelpers.ParseQuery(uri.Query).TryGetValue(key, out var valueFromQueryString))
{
if (typeof(T) == typeof(int) && int.TryParse(valueFromQueryString, out var valueAsInt))
{
value = (T)(object)valueAsInt;
return true;
}

if (typeof(T) == typeof(string))
{
value = (T)(object)valueFromQueryString.ToString();
return true;
}

if (typeof(T) == typeof(decimal) && decimal.TryParse(valueFromQueryString, out var valueAsDecimal))
{
value = (T)(object)valueAsDecimal;
return true;
}
}

value = default;
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace BlazorDemo.Models
{
public class SendTweetViewModel
{
[DisplayName("Tweet Text:")]
[Required]
[DataType(DataType.MultilineText)]
public string Text { get; set; }


public string Response { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace BlazorDemo.Models
{
public class TweetViewModel
{
[DisplayName("Image")]
[DataType(DataType.ImageUrl)]
public string ImageUrl { get; set; }

[DisplayName("Screen Name")]
public string ScreenName { get; set; }

[DisplayName("Tweet")]
public string Text { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
@page "/error"


<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>

<h3>Development Mode</h3>
<p>
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
@page "/"
@implements IDisposable
@using LinqToTwitter
@using BlazorDemo.Models
@using System.Text.RegularExpressions
@inject BlazorDemo.Services.BlazorAuthorizer BlazorAuthorizer

<TwitterApplicationAuth />

@if (BlazorAuthorizer.CredentialStore != null)
{
<h4>Tweets for @BlazorAuthorizer.CredentialStore.ScreenName</h4>

<button class="btn btn-primary" @onclick="GetTweets">Get Tweets</button>
<button class="btn btn-primary" @onclick="OpenPopup">Send Tweet</button>
<br />
<br />
@foreach (var tweet in tweets)
{
<dl>
<dt><img src="@tweet.ImageUrl" /> @@<a href=@("https://twitter.com/"[email protected]) target="_blank">@tweet.ScreenName</a></dt>
<dd>@((MarkupString)tweet.Text)</dd>
</dl>
}

@if (ShowPopup)
{
<div class="modal" tabindex="-1" style="display:block" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">Send Tweet</h3>
<!-- Button to close the popup -->
<button type="button" class="close"
@onclick="ClosePopup">
<span aria-hidden="true">X</span>
</button>
</div>
<div class="modal-body">
<input class="form-control" type="text"
placeholder="Compose a Tweet..."
@bind="NewTweet" />
<br /><br />
<button class="btn btn-primary"
@onclick="SendTweet">
Save
</button>
<br />
</div>
</div>
</div>
</div>
}
}

@code {
public List<TweetViewModel> tweets = new List<TweetViewModel>();
bool ShowPopup = false;
string NewTweet = "";

protected override void OnInitialized()
{
// Subscribe to the StateChanged EventHandler
BlazorAuthorizer.StateChanged += OnBlazorAuthorizerStateChanged;
}

// This method is fired when the BlazorAuthorizer object
// invokes its StateHasChanged() method
// This will cause this control to invoke its own
// StateHasChanged() method
void OnBlazorAuthorizerStateChanged(object sender, EventArgs e)
{
StateHasChanged();
}

void IDisposable.Dispose()
{
// When this control is disposed of
// unsubscribe from the StateChanged EventHandler
BlazorAuthorizer.StateChanged -= OnBlazorAuthorizerStateChanged;
}

void OpenPopup()
{
NewTweet = "";
// Open the Popup
ShowPopup = true;
}

void ClosePopup()
{
// Close the Popup
ShowPopup = false;
}

async Task GetTweets()
{
var ctx = new TwitterContext(BlazorAuthorizer);

tweets = await (from tweet in ctx.Status
where tweet.Type == StatusType.Home &&
tweet.TweetMode == TweetMode.Extended
select new TweetViewModel
{
ImageUrl = tweet.User.ProfileImageUrl,
ScreenName = tweet.User.ScreenNameResponse,
Text = CreateActiveLinks(tweet.FullText)
}).ToListAsync();
}

async Task SendTweet()
{
var ctx = new TwitterContext(BlazorAuthorizer);

Status responseTweet = await ctx.TweetAsync(NewTweet);

await GetTweets();

ClosePopup();
}

// Utility
/// <summary>
/// From: https://www.mikesdotnetting.com/article/140/converting-urls-into-links-with-regex
/// Finds web and email addresses in a string and surrounds then with the appropriate HTML anchor tags
/// </summary>
/// <param name="s"></param>
/// <returns>String</returns>
public string CreateActiveLinks(string s)
{
//Finds URLs with no protocol
var urlregex = new Regex(@"\b\({0,1}(?<url>(www|ftp)\.[^ ,""\s<)]*)\b",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
//Finds URLs with a protocol
var httpurlregex = new Regex(@"\b\({0,1}(?<url>[^>](http://www\.|http://|https://|ftp://)[^,""\s<)]*)\b",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
//Finds email addresses
var emailregex = new Regex(@"\b(?<mail>[a-zA-Z_0-9.-]+\@[a-zA-Z_0-9.-]+\.\w+)\b",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
s = urlregex.Replace(s, " <a href=\"http://${url}\" target=\"_blank\">${url}</a>");
s = httpurlregex.Replace(s, " <a href=\"${url}\" target=\"_blank\">${url}</a>");
s = emailregex.Replace(s, "<a href=\"mailto:${mail}\">${mail}</a>");
return s;
}
}
Loading

0 comments on commit 3c58f49

Please sign in to comment.