اینجور که من متوجه شدم با استفاده از این روش نمیتوان کاری کرد که با بستن مرورگر، کاربر از حساب کاربری خود خارج شود!
درسته؟
// See https://aka.ms/new-console-template for more information Console.WriteLine("Hello, World!");
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net6.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> </Project>
global using System;
global using static System.Console;
<ImplicitUsings>enable</ImplicitUsings>
// <auto-generated/> global using global::System; global using global::System.Collections.Generic; global using global::System.IO; global using global::System.Linq; global using global::System.Net.Http; global using global::System.Threading; global using global::System.Threading.Tasks;
// <autogenerated /> global using global::System; global using global::System.Collections.Generic; global using global::System.IO; global using global::System.Linq; global using global::System.Net.Http; global using global::System.Threading; global using global::System.Threading.Tasks; global using global::System.Net.Http.Json; global using global::Microsoft.AspNetCore.Builder; global using global::Microsoft.AspNetCore.Hosting; global using global::Microsoft.AspNetCore.Http; global using global::Microsoft.AspNetCore.Routing; global using global::Microsoft.Extensions.Configuration; global using global::Microsoft.Extensions.DependencyInjection; global using global::Microsoft.Extensions.Hosting; global using global::Microsoft.Extensions.Logging;
<ItemGroup> <Import Remove="System.Threading" /> <Import Include="Microsoft.Extensions.Logging" /> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net472'"> </ItemGroup>
using Microsoft.AspNetCore.Mvc; namespace AngularTemplateDrivenFormsLab.Controllers { [Route("api/[controller]")] public class ShowImagesController : Controller { [HttpGet("[action]")] public IActionResult GetImage() { return File("~/assets/resume.png", "image/png"); } } }
import { Injectable } from "@angular/core"; import { Observable } from "rxjs/Observable"; import { HttpClient } from "@angular/common/http"; @Injectable() export class DownloadBinaryDataService { constructor(private httpClient: HttpClient) { } public getImage(): Observable<Blob> { return this.httpClient.get("/api/ShowImages/GetImage", { responseType: "blob" }); } }
import { Injectable } from "@angular/core"; function getWindow(): any { return window; } @Injectable() export class WindowRefService { get nativeWindow(): any { return getWindow(); } }
import { WindowRefService } from "./window.service"; @NgModule({ providers: [ WindowRefService ] }) export class CoreModule {}
const urlCreator = this.nativeWindow.URL; imageBlobUrl = urlCreator.createObjectURL(imageDataBlob);
<img src="blob:http://localhost:5000/9d4bae44-00bc-4ed8-9f27-cac2de5ecd5d">
img-src 'self' data: blob:
import { WindowRefService } from "./../../core/window.service"; import { DownloadBinaryDataService } from "app/angular-http-client-blob/download-binary-data.service"; import { Component, OnInit, ViewChild, ElementRef } from "@angular/core"; import { DomSanitizer, SafeUrl } from "@angular/platform-browser"; @Component({ templateUrl: "./download-blobs.component.html", styleUrls: ["./download-blobs.component.css"] }) export class DownloadBlobsComponent implements OnInit { @ViewChild("sampleImage1") sampleImage1: ElementRef; private nativeWindow: Window; imageBlobUrl: string; sanitizedImageBlobUrl: SafeUrl; constructor(private downloadService: DownloadBinaryDataService, private windowRefService: WindowRefService, private sanitizer: DomSanitizer) { } ngOnInit() { this.nativeWindow = this.windowRefService.nativeWindow; this.downloadService.getImage().subscribe(imageDataBlob => { const urlCreator = this.nativeWindow.URL; this.imageBlobUrl = urlCreator.createObjectURL(imageDataBlob); // doesn't work -> <img [src]="imageBlobUrl"> this.sampleImage1.nativeElement.src = this.imageBlobUrl; // works -> <img #sampleImage1> this.sanitizedImageBlobUrl = this.sanitizer.bypassSecurityTrustUrl(this.imageBlobUrl); // works -> <img [src]="sanitizedImageBlobUrl"> }); } }
<h1>Angular HttpClient Blob</h1> <h4>#sampleImage1</h4> <img #sampleImage1> <h4>imageBlobUrl</h4> <img [src]="imageBlobUrl"> <h4>sanitizedImageBlobUrl</h4> <img [src]="sanitizedImageBlobUrl">
this.imageBlobUrl = urlCreator.createObjectURL(imageDataBlob); // doesn't work -> <img [src]="imageBlobUrl">
<h4>imageBlobUrl</h4> <img [src]="imageBlobUrl">
<img _ngcontent-c1="" src="unsafe:blob:http://localhost:5000/a4505339-5da2-4303-949c-8e6a7cfff2fc">
Refused to load the image 'unsafe:blob:http://localhost:5000/a4505339-5da2-4303-949c-8e6a7cfff2fc' because it violates the following Content Security Policy directive: "img-src 'self' data: blob:".
this.sanitizedImageBlobUrl = this.sanitizer.bypassSecurityTrustUrl(this.imageBlobUrl); // works -> <img [src]="sanitizedImageBlobUrl">
<img [src]="sanitizedImageBlobUrl">
<img _ngcontent-c1="" src="blob:http://localhost:5000/a4505339-5da2-4303-949c-8e6a7cfff2fc">
<img #sampleImage1>
@ViewChild("sampleImage1") sampleImage1: ElementRef;
this.sampleImage1.nativeElement.src = this.imageBlobUrl; // works -> <img #sampleImage1>
<ng-component _nghost-c1=""><h1 _ngcontent-c1="">Angular HttpClient Blob</h1> <h4 _ngcontent-c1="">#sampleImage1</h4> <img _ngcontent-c1="" src="blob:http://localhost:5000/a4505339-5da2-4303-949c-8e6a7cfff2fc"> <h4 _ngcontent-c1="">imageBlobUrl</h4> <img _ngcontent-c1="" src="unsafe:blob:http://localhost:5000/a4505339-5da2-4303-949c-8e6a7cfff2fc"> <h4 _ngcontent-c1="">sanitizedImageBlobUrl</h4> <img _ngcontent-c1="" src="blob:http://localhost:5000/a4505339-5da2-4303-949c-8e6a7cfff2fc"> </ng-component>
> create-react-app state-management-with-mobx-part4 > cd state-management-with-mobx-part4
> npm install --save bootstrap mobx mobx-react mobx-react-devtools mobx-state-tree
> npm install --save-dev babel-eslint customize-cra eslint eslint-config-react-app eslint-loader eslint-plugin-babel eslint-plugin-css-modules eslint-plugin-filenames eslint-plugin-flowtype eslint-plugin-import eslint-plugin-no-async-without-await eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-react-redux eslint-plugin-redux-saga eslint-plugin-simple-import-sort react-app-rewired typescript
const products = [ { id: 1, name: "Item 1", price: 850 }, { id: 2, name: "Item 2", price: 900 }, { id: 3, name: "Item 3", price: 1500 }, { id: 4, name: "Item 4", price: 1000 } ]; export default products;
import React from "react"; import products from "../services/productsService"; const ShopItemsList = ({ onAdd }) => { return ( <table className="table table-hover"> <thead className="thead-light"> <tr> <th>Name</th> <th>Price</th> <th>Action</th> </tr> </thead> <tbody> {products.map(product => ( <tr key={product.id}> <td>{product.name}</td> <td>{product.price}</td> <td> <button className="btn btn-sm btn-info" onClick={() => onAdd(product)} > Add </button> </td> </tr> ))} </tbody> </table> ); }; export default ShopItemsList;
import React from "react"; const BasketItemsList = ({ items, totalPrice, onRemove }) => { return ( <> <table className="table table-hover"> <thead className="thead-light"> <tr> <th>Name</th> <th>Price</th> <th>Count</th> <th>Action</th> </tr> </thead> <tbody> {items.map(item => ( <tr key={item.id}> <td>{item.name}</td> <td>{item.price}</td> <td>{item.count}</td> <td> <button className="btn btn-sm btn-danger" onClick={() => onRemove(item.id)} > Remove </button> </td> </tr> ))} <tr> <td align="right"> <strong>Total: </strong> </td> <td> <strong>{totalPrice}</strong> </td> <td></td> <td></td> </tr> </tbody> </table> </> ); }; export default BasketItemsList;
const BasketItemsList = ({ items, totalPrice, onRemove }) => {
import React, { Component } from "react"; class BasketItemsCounter extends Component { render() { const { count, onRemoveAll } = this.props; return ( <div> <h1>Total items: {count}</h1> <button type="button" className="btn btn-sm btn-danger" onClick={() => onRemoveAll()} > Empty Basket </button> </div> ); } } export default BasketItemsCounter;
import React, { Component } from "react"; import BasketItemsCounter from "./components/BasketItemsCounter"; import BasketItemsList from "./components/BasketItemsList"; import ShopItemsList from "./components/ShopItemsList"; class App extends Component { render() { return ( <main className="container"> <div className="row"> <BasketItemsCounter /> </div> <hr /> <div className="row"> <h2>Products</h2> <ShopItemsList /> </div> <div className="row"> <h2>Basket</h2> <BasketItemsList /> </div> </main> ); } } export default App;
import { action, observable } from "mobx"; export default class CounterStore { @observable totalNumbersInBasket = 0; constructor(rootStore) { this.rootStore = rootStore; } @action increase = () => { this.totalNumbersInBasket++; }; @action decrease = () => { this.totalNumbersInBasket--; }; }
import { action, computed, observable } from "mobx"; export default class MarketStore { @observable basketItems = []; constructor(rootStore) { this.rootStore = rootStore; } @action add = product => { const selectedItem = this.basketItems.find(item => item.id === product.id); if (selectedItem) { selectedItem.count++; } else { this.basketItems.push({ ...product, count: 1 }); } this.rootStore.counterStore.increase(); }; @action remove = id => { const selectedItem = this.basketItems.find(item => item.id === id); selectedItem.count--; if (selectedItem.count === 0) { this.basketItems.remove(selectedItem); } this.rootStore.counterStore.decrease(); }; @action removeAll = () => { this.basketItems = []; this.rootStore.counterStore.totalNumbersInBasket = 0; }; @computed get totalPrice() { return this.basketItems.reduce((previous, current) => { return previous + current.price * current.count; }, 0); } }
import CounterStore from "./counter"; import MarketStore from "./market"; class RootStore { counterStore = new CounterStore(this); marketStore = new MarketStore(this); } export default RootStore;
export default class MarketStore { @observable basketItems = []; constructor(rootStore) { this.rootStore = rootStore; } @action removeAll = () => { this.basketItems = []; this.rootStore.counterStore.totalNumbersInBasket = 0; }; }
import "./index.css"; import "bootstrap/dist/css/bootstrap.css"; import makeInspectable from "mobx-devtools-mst"; import { Provider } from "mobx-react"; import React from "react"; import ReactDOM from "react-dom"; import App from "./App"; import * as serviceWorker from "./serviceWorker"; import RootStore from "./stores"; const rootStore = new RootStore(); if (process.env.NODE_ENV === "development") { makeInspectable(rootStore); // https://github.com/mobxjs/mobx-devtools } ReactDOM.render( <Provider {...rootStore}> <App /> </Provider>, document.getElementById("root") ); serviceWorker.unregister();
<Provider counterStore={rootStore.counterStore} marketStore={rootStore.marketStore}>
import { inject, observer } from "mobx-react"; import React from "react"; import products from "../services/productsService"; const ShopItemsList = ({ onAdd }) => { return ( // ... ); }; export default inject(({ marketStore }) => ({ onAdd: marketStore.add }))(observer(ShopItemsList));
import { inject, observer } from "mobx-react"; import React from "react"; const BasketItemsList = ({ items, totalPrice, onRemove }) => { return ( // ... ); }; export default inject(({ marketStore }) => ({ items: marketStore.basketItems, totalPrice: marketStore.totalPrice, onRemove: marketStore.remove }))(observer(BasketItemsList));
import { inject, observer } from "mobx-react"; import React, { Component } from "react"; @inject(rootStore => ({ count: rootStore.counterStore.totalNumbersInBasket, onRemoveAll: rootStore.marketStore.removeAll })) @observer class BasketItemsCounter extends Component { render() { const { count, onRemoveAll } = this.props; return ( // ... ); } } export default BasketItemsCounter;