06 Mar 2020
直接上 code
Google Login Button
google-login-button.component.html
<button id="googleBtn" type="submit">
透過Google登入
</button>
google-login-button.component.ts
import { Component, OnInit, ElementRef, AfterViewInit } from '@angular/core';
declare var gapi: any;
@Component({
selector: 'app-google-login-button',
templateUrl: './google-login-button.component.html',
styleUrls: ['./google-login-button.component.scss']
})
export class GoogleLoginButtonComponent implements OnInit, AfterViewInit {
clientId = 'clientId';
scope = [
'profile',
'email'
].join(' ');
auth2: any;
constructor(private element: ElementRef) { }
ngOnInit(): void {
let script = document.getElementById('google-platform') as HTMLScriptElement;
if (!script) {
script = document.createElement('script');
script.id = 'google-platform';
script.src = `https://apis.google.com/js/platform.js`;
script.async = true;
script.defer = true;
document.body.appendChild(script);
}
}
ngAfterViewInit() {
this.load();
}
load() {
if (typeof gapi === undefined || typeof gapi === 'undefined') {
this.checkLoaded();
return;
}
if (typeof gapi.load !== 'function') {
this.checkLoaded();
return;
}
gapi.load('auth2', () => {
this.auth2 = gapi.auth2.init({
client_id: this.clientId,
cookiepolicy: 'single_host_origin',
scope: this.scope
});
this.attachSignin(this.element.nativeElement.firstChild);
});
}
checkLoaded() {
setTimeout(() => {
this.load();
}, 100);
}
attachSignin(element: any) {
this.auth2.attachClickHandler(element, {},
(googleUser) => {
const profile = googleUser.getBasicProfile();
const auth = googleUser.getAuthResponse();
const user = {
userId: profile.getId(),
name: profile.getName(),
email: profile.getEmail(),
expiredTime: new Date(auth.expires_at),
accessToken: auth.access_token,
};
console.log(user);
}, (error: any) => {
console.log(JSON.stringify(error, undefined, 2));
});
}
}
facebook-login-button.component.html
<button (click)="submit();">
透過Facebook登入
</button>
facebook-login-button.component.ts
import { Component, AfterViewInit } from '@angular/core';
declare var FB: any;
@Component({
selector: 'app-facebook-login-button',
templateUrl: './facebook-login-button.component.html',
styleUrls: ['./facebook-login-button.component.scss']
})
export class FacebookLoginButtonComponent implements AfterViewInit {
appId = 'appId';
version = 'v6.0';
scope = 'public_profile,email';
constructor() { }
ngAfterViewInit() {
let script = document.getElementById('facebook-platform') as HTMLScriptElement;
if (!script) {
script = document.createElement('script');
script.id = 'facebook-platform';
script.src = `https://connect.facebook.net/en_US/sdk.js`;
script.async = true;
script.defer = true;
document.body.appendChild(script);
}
(window as any).fbAsyncInit = () => {
FB.init({
appId: this.appId,
cookie: true,
xfbml: true,
version: this.version
});
};
}
submit() {
FB.login(login => {
if (login.status !== 'connected' || !login.authResponse) {
console.log('User login failed');
return;
}
FB.api('/me', 'GET', { fields: 'id,name,email,first_name,last_name,link,age_range,picture,birthday' }, userInfo => {
const user = {
userId: userInfo.id,
name: userInfo.name,
email: userInfo.email,
expiredTime: new Date(login.authResponse.data_access_expiration_time * 1000),
accessToken: login.authResponse.accessToken,
};
console.log(user);
});
}, { scope: this.scope });
}
}
23 Feb 2020
使用 npm 更新,首先移除 Angular CLI
npm uninstall -g angular-cli
再重新安裝
npm install -g @angular/cli@latest
20 Oct 2019
直接上 code
專案加入 GeoAPI
dotnet add package GeoAPI
add GeoJsonConverter
class
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using GeoAPI.Geometries;
public class GeoJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(IGeometry) || objectType.GetInterface("GeoAPI.Geometries.IGeometry") == typeof(IGeometry);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType != JsonToken.StartObject)
{
return null;
}
var jObj = JObject.Load(reader);
return jObj.ToGeometry();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var geo = value as IGeometry;
serializer.Serialize(writer, geo.ToJsonObject());
}
}
in Startup.cs
public void ConfigureServices(IServiceCollection services)
{
//...
services.AddMvc(config =>
{
// ...
}).AddJsonOptions(options =>
{
options.SerializerSettings.Converters.Add(new GeoJsonConverter()); // 加上GeoJsonConverter
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
Update
For .NET Core 3.1
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using NetTopologySuite.Geometries;
public class GeoJsonConverter : JsonConverter<Geometry>
{
public override Geometry Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartObject)
{
throw new JsonException();
}
if (!JsonDocument.TryParseValue(ref reader, out var doc))
{
throw new JsonException();
}
if (doc.RootElement.TryGetProperty("type", out var geoJsonType))
{
throw new JsonException();
}
var json = JsonSerializer.Serialize(doc);
switch (geoJsonType.GetString())
{
case "Point":
return ParseToGeometry<Point>(json);
case "MultiPoint":
return ParseToGeometry<MultiPoint>(json);
case "LineString":
return ParseToGeometry<LineString>(json);
case "MultiLineString":
return ParseToGeometry<MultiLineString>(json);
case "Polygon":
return ParseToGeometry<Polygon>(json);
case "MultiPolygon":
return ParseToGeometry<MultiPolygon>(json);
case "GeometryCollection":
return ParseToGeometry<GeometryCollection>(json);
}
throw new JsonException();
}
private static Geometry ParseToGeometry<T>(string json) where T : Geometry => new NetTopologySuite.IO.GeoJsonReader().Read<T>(json);
public override void Write(Utf8JsonWriter writer, Geometry value, JsonSerializerOptions options)
{
var geoJsonWriter = new NetTopologySuite.IO.GeoJsonWriter();
var json = geoJsonWriter.Write(value);
var doc = JsonDocument.Parse(json);
doc.WriteTo(writer);
}
}
15 Oct 2019
first in .csproj
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>1.0.0</Version>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<Company></Company>
<Authors>David</Authors>
<PackageProjectUrl>https://github.com/davidyujia/</PackageProjectUrl>
<PackageIconUrl></PackageIconUrl>
<PackageTags>generic repository</PackageTags>
<Copyright></Copyright>
<Description></Description>
<PackageLicenseUrl></PackageLicenseUrl>
<NeutralLanguage>en</NeutralLanguage>
<RepositoryUrl>https://github.com/davidyujia/</RepositoryUrl>
<RepositoryType>git</RepositoryType>
</PropertyGroup>
then
dotnet pack -c Release
29 Jul 2019
直接上 code
Install
dotnet add package System.Reactive
using
using System.Reactive;
using System.Reactive.Subjects;
Observable
public class ObjectObservable : ObservableBase<object>
{
private readonly Subject<object> _subject = new Subject<object>();
public void Submit(object item)
{
_subject.OnNext(item);
}
protected override IDisposable SubscribeCore(IObserver<object> observer)
{
return _subject.Subscribe(observer);
}
}
Observer
public class ObjectObserver : ObserverBase<object>, IDisposable
{
private IDisposable _cancellation;
public void Subscribe(IObservable<object> provider)
{
_cancellation = provider.Subscribe(this);
}
public void Dispose()
{
_cancellation.Dispose();
_cancellation = null;
}
protected override void OnNextCore(object item)
{
//when call "OnNext"...
}
protected override void OnErrorCore(Exception error)
{
throw error;
}
protected override void OnCompletedCore()
{
//when call "OnCompleted" or "Dispose"...
}
}
HOW TO
var observable = new ObjectObservable()
observable.Submit(new object());
var observer1 = new ObjectObserver();
var unsubscribe1 = observable.Subscribe(observer1);
observable.Submit(new object());
var observer2 = new ObjectObserver();
observable.Subscribe(observer2);
observable.Submit(new object());
//unsubscribe "observer1"
unsubscribe1.Dispose();