using Discord.Commands;
using Discord;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading.Tasks;
using NadekoBot.Services;
using System.Threading;
using System.Collections.Generic;
using NadekoBot.Services.Database.Models;
using System.Net.Http;
using NadekoBot.Attributes;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using NLog;
using NadekoBot.Extensions;
using System.Diagnostics;
namespace NadekoBot.Modules.Searches
{
public partial class Searches
{
public class StreamStatus
{
public bool IsLive { get; set; }
public string ApiLink { get; set; }
public string Views { get; set; }
public string Game { get; set; }
public string Status { get; set;}
}
public class HitboxResponse {
public bool Success { get; set; } = true;
[JsonProperty("media_is_live")]
public string MediaIsLive { get; set; }
public bool IsLive => MediaIsLive == "1";
[JsonProperty("media_views")]
public string Views { get; set; }
}
public class TwitchResponse
{
public string Error { get; set; } = null;
public bool IsLive => Stream != null;
public StreamInfo Stream { get; set; }
public class StreamInfo
{
public int Viewers { get; set; }
public string Game { get; set; }
public ChannelInfo Channel { get; set;}
public class ChannelInfo {
public string Status { get; set; )
}
}
}
public class BeamResponse
{
public string Error { get; set; } = null;
[JsonProperty("online")]
public bool IsLive { get; set; }
public int ViewersCurrent { get; set; }
}
public class StreamNotFoundException : Exception
{
public StreamNotFoundException(string message) : base("Stream '" + message + "' not found.")
{
}
}
[Group]
public class StreamNotificationCommands : ModuleBase
{
private static Timer checkTimer { get; }
private static ConcurrentDictionary<string, StreamStatus> oldCachedStatuses = new ConcurrentDictionary<string, StreamStatus>();
private static ConcurrentDictionary<string, StreamStatus> cachedStatuses = new ConcurrentDictionary<string, StreamStatus>();
private static Logger _log { get; }
private static bool FirstPass { get; set; } = true;
static StreamNotificationCommands()
{
_log = LogManager.GetCurrentClassLogger();
checkTimer = new Timer(async (state) =>
{
oldCachedStatuses = new ConcurrentDictionary<string, StreamStatus>(cachedStatuses);
cachedStatuses.Clear();
IEnumerable<FollowedStream> streams;
using (var uow = DbHandler.UnitOfWork())
{
streams = uow.GuildConfigs.GetAllFollowedStreams();
}
await Task.WhenAll(streams.Select(async fs =>
{
try
{
var newStatus = await GetStreamStatus(fs).ConfigureAwait(false);
if (FirstPass)
{
return;
}
StreamStatus oldStatus;
if (oldCachedStatuses.TryGetValue(newStatus.ApiLink, out oldStatus) &&
(oldStatus.IsLive != newStatus.IsLive)
{
var server = NadekoBot.Client.GetGuild(fs.GuildId);
if (server == null)
return;
var channel = server.GetTextChannel(fs.ChannelId);
if (channel == null)
return;
try
{
var msg = await channel.EmbedAsync(fs.GetEmbed(newStatus)).ConfigureAwait(false);
}
catch { }
}
}
catch { }
}));
FirstPass = false;
}, null, TimeSpan.Zero, TimeSpan.FromSeconds(60));
}
private static async Task<StreamStatus> GetStreamStatus(FollowedStream stream, bool checkCache = true)
{
string response;
StreamStatus result;
switch (stream.Type)
{
case FollowedStream.FollowedStreamType.Hitbox:
var hitboxUrl = $"https://api.hitbox.tv/media/status/{stream.Username.ToLowerInvariant()}";
if (checkCache && cachedStatuses.TryGetValue(hitboxUrl, out result))
return result;
using (var http = new HttpClient())
{
response = await http.GetStringAsync(hitboxUrl).ConfigureAwait(false);
}
var hbData = JsonConvert.DeserializeObject<HitboxResponse>(response);
if (!hbData.Success)
throw new StreamNotFoundException($"{stream.Username} [{stream.Type}]");
result = new StreamStatus()
{
IsLive = hbData.IsLive,
ApiLink = hitboxUrl,
Views = hbData.Views
};
cachedStatuses.AddOrUpdate(hitboxUrl, result, (key, old) => result);
return result;
case FollowedStream.FollowedStreamType.Twitch:
var twitchUrl = $"https://api.twitch.tv/kraken/streams/{Uri.EscapeUriString(stream.Username.ToLowerInvariant())}?client_id=67w6z9i09xv2uoojdm9l0wsyph4hxo6";
if (checkCache && cachedStatuses.TryGetValue(twitchUrl, out result))
return result;
using (var http = new HttpClient())
{
response = await http.GetStringAsync(twitchUrl).ConfigureAwait(false);
}
var twData = JsonConvert.DeserializeObject<TwitchResponse>(response);
if (twData.Error != null)
{
throw new StreamNotFoundException($"{stream.Username} [{stream.Type}]");
}
result = new StreamStatus()
{
IsLive = twData.IsLive,
ApiLink = twitchUrl,
Views = twData.Stream?.Viewers.ToString() ?? "0"
Game = twData.Stream?.Game,
Status = twData.Stream?.Channel?.Status
};
cachedStatuses.AddOrUpdate(twitchUrl, result, (key, old) => result);
return result;
case FollowedStream.FollowedStreamType.Beam:
var beamUrl = $"https://beam.pro/api/v1/channels/{stream.Username.ToLowerInvariant()}";
if (checkCache && cachedStatuses.TryGetValue(beamUrl, out result))
return result;
using (var http = new HttpClient())
{
response = await http.GetStringAsync(beamUrl).ConfigureAwait(false);
}
var bmData = JsonConvert.DeserializeObject<BeamResponse>(response);
if (bmData.Error != null)
throw new StreamNotFoundException($"{stream.Username} [{stream.Type}]");
result = new StreamStatus()
{
IsLive = bmData.IsLive,
ApiLink = beamUrl,
Views = bmData.ViewersCurrent.ToString()
};
cachedStatuses.AddOrUpdate(beamUrl, result, (key, old) => result);
return result;
default:
break;
}
return null;
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[RequireUserPermission(GuildPermission.ManageMessages)]
public async Task Hitbox([Remainder] string username) =>
await TrackStream((ITextChannel)Context.Channel, username, FollowedStream.FollowedStreamType.Hitbox)
.ConfigureAwait(false);
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[RequireUserPermission(GuildPermission.ManageMessages)]
public async Task Twitch([Remainder] string username) =>
await TrackStream((ITextChannel)Context.Channel, username, FollowedStream.FollowedStreamType.Twitch)
.ConfigureAwait(false);
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[RequireUserPermission(GuildPermission.ManageMessages)]
public async Task Beam([Remainder] string username) =>
await TrackStream((ITextChannel)Context.Channel, username, FollowedStream.FollowedStreamType.Beam)
.ConfigureAwait(false);
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
public async Task ListStreams()
{
IEnumerable<FollowedStream> streams;
using (var uow = DbHandler.UnitOfWork())
{
streams = uow.GuildConfigs
.For(Context.Guild.Id,
set => set.Include(gc => gc.FollowedStreams))
.FollowedStreams;
}
if (!streams.Any())
{
await Context.Channel.SendConfirmAsync("You are not following any streams on this server.").ConfigureAwait(false);
return;
}
var text = string.Join("\n", await Task.WhenAll(streams.Select(async snc =>
{
var ch = await Context.Guild.GetTextChannelAsync(snc.ChannelId);
return $"`{snc.Username}`'s stream on **{(ch)?.Name}** channel. 【`{snc.Type.ToString()}`】";
})));
await Context.Channel.SendConfirmAsync($"You are following **{streams.Count()}** streams on this server.\n\n" + text).ConfigureAwait(false);
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[RequireUserPermission(GuildPermission.ManageMessages)]
public async Task RemoveStream(FollowedStream.FollowedStreamType type, [Remainder] string username)
{
username = username.ToLowerInvariant().Trim();
var fs = new FollowedStream()
{
ChannelId = Context.Channel.Id,
Username = username,
Type = type
};
bool removed;
using (var uow = DbHandler.UnitOfWork())
{
var config = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(gc => gc.FollowedStreams));
removed = config.FollowedStreams.Remove(fs);
if (removed)
await uow.CompleteAsync().ConfigureAwait(false);
}
if (!removed)
{
await Context.Channel.SendErrorAsync("No such stream.").ConfigureAwait(false);
return;
}
await Context.Channel.SendConfirmAsync($"Removed `{username}`'s stream ({type}) from notifications.").ConfigureAwait(false);
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
public async Task CheckStream(FollowedStream.FollowedStreamType platform, [Remainder] string username)
{
var stream = username?.Trim();
if (string.IsNullOrWhiteSpace(stream))
return;
try
{
var streamStatus = (await GetStreamStatus(new FollowedStream
{
Username = stream,
Type = platform,
}));
if (streamStatus.IsLive)
{
await Context.Channel.SendConfirmAsync($"Streamer {username} is online with {streamStatus.Views} viewers.");
}
else
{
await Context.Channel.SendConfirmAsync($"Streamer {username} is offline.");
}
}
catch
{
await Context.Channel.SendErrorAsync("No channel found.");
}
}
private static async Task TrackStream(ITextChannel channel, string username, FollowedStream.FollowedStreamType type)
{
username = username.ToLowerInvariant().Trim();
var fs = new FollowedStream
{
GuildId = channel.Guild.Id,
ChannelId = channel.Id,
Username = username,
Type = type,
};
StreamStatus status;
try
{
status = await GetStreamStatus(fs).ConfigureAwait(false);
}
catch
{
await channel.SendErrorAsync("Stream probably doesn't exist.").ConfigureAwait(false);
return;
}
using (var uow = DbHandler.UnitOfWork())
{
uow.GuildConfigs.For(channel.Guild.Id, set => set.Include(gc => gc.FollowedStreams))
.FollowedStreams
.Add(fs);
await uow.CompleteAsync().ConfigureAwait(false);
}
await channel.EmbedAsync(fs.GetEmbed(status), $"🆗 I will notify this channel when status changes.").ConfigureAwait(false);
}
}
}
public static class FollowedStreamExtensions
{
public static EmbedBuilder GetEmbed(this FollowedStream fs, Searches.StreamStatus status)
{
var embed = new EmbedBuilder().WithTitle(fs.Username)
.WithUrl(fs.GetLink())
.WithThumbnailUrl(fs.GetLink())
.WithDescription(status.Status)
.AddField(efb => efb.WithName("Status")
.WithValue(status.IsLive ? "Online" : "Offline")
.WithIsInline(true))
.AddField(efb => efb.WithName("Viewers")
.WithValue(status.IsLive ? status.Views : "-")
.WithIsInline(true))
.AddField(efb => efb.WithName("Game">
.WithValue(status.Game)
.WithIsInlin(true))
.AddField(efb => efb.WithName("Platform")
.WithValue(fs.Type.ToString())
.WithIsInline(true))
.WithColor(status.IsLive ? "NadekoBot.OkColor" : "NadekoBot.ErrorColor");
return embed;
}
public static string GetLink(this FollowedStream fs) {
if (fs.Type == FollowedStream.FollowedStreamType.Hitbox)
return $"http://www.hitbox.tv/{fs.Username}/";
else if (fs.Type == FollowedStream.FollowedStreamType.Twitch)
return $"http://www.twitch.tv/{fs.Username}/";
else if (fs.Type == FollowedStream.FollowedStreamType.Beam)
return $"https://beam.pro/{fs.Username}/";
else
return "??";
}
}
}
I'm attempting to get this discord bot to announce when someone streaming on Twitch goes Live by amending its code to give me more information (ie Game and Status) but I keep getting an error that I can't for the life of me find and fix! I was told the issue is between coding on a PC and coding on a Mac? Not sure that's 100% accurate. Can someone please run this code and help me get this to work properly? Thanks!
Related
VS Code suggested i install Solidity extension which I did. immediately it installed it required that I update my solidity to 0.8.17; I did then I had to update some parts of the code. after I did, I tested on remix and it worked. Back on vs code now and I've been trying to compile but it is not compiling.It creates the 'build' folder but doesn't write any JSON files in it.
Campaign.sol file:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;
contract CampaignFactory {
address[] public deployedCampaigns;
function createCampaign(uint minimum) public {
Campaign newCampaign = new Campaign(minimum, msg.sender);
deployedCampaigns.push(address(newCampaign));
}
function getDeployedCampaigns() public view returns (address[] memory) {
return deployedCampaigns;
}
}
contract Campaign {
struct Request {
string description;
uint value;
address payable recipient;
bool complete;
uint approvalCount;
mapping(address => bool) approvals;
}
Request[] public requests;
address public manager;
uint public minimumContribution;
mapping(address => bool) public approvers;
uint public approversCount;
modifier restricted() {
require(msg.sender == manager);
_;
}
constructor (uint minimum, address creator) {
manager = creator;
minimumContribution = minimum;
}
function contribute() public payable {
require(msg.value > minimumContribution);
approvers[msg.sender] = true;
approversCount++;
}
function createRequest(string memory description, uint value, address payable recipient) public restricted {
Request storage newRequest = requests.push();
newRequest.description = description;
newRequest.value = value;
newRequest.recipient = recipient;
newRequest.complete = false;
newRequest.approvalCount = 0;
}
function approveRequest(uint index) public {
Request storage request = requests[index];
require(approvers[msg.sender]);
require(!request.approvals[msg.sender]);
request.approvals[msg.sender] = true;
request.approvalCount++;
}
function finalizeRequest(uint index) public restricted {
Request storage request = requests[index];
require(request.approvalCount > (approversCount / 2));
require(!request.complete);
request.recipient.transfer(request.value);
request.complete = true;
}
function getSummary() public view returns (
uint, uint, uint, uint, address
) {
return(
minimumContribution,
address(this).balance,
requests.length,
approversCount,
manager
);
}
function getRequestsCount() public view returns (uint) {
return requests.length;
}
}
compile.js file
const path = require("path");
const solc = require("solc");
const fs = require("fs-extra");
const buildPath = path.resolve(__dirname, "build");
fs.removeSync(buildPath);
const campaignPath = path.resolve(__dirname, "contracts", "Campaign.sol");
const source = fs.readFileSync(campaignPath, "utf8");
const output = solc.compile(source, 1).contracts;
fs.ensureDirSync(buildPath);
for (let contract in output) {
fs.outputJsonSync(
path.resolve(buildPath, contract.replace(":", "") + ".json"),
output[contract]
);
}
i'm learning blockchain dev and now i'm trying to mint an NFT, the process is ok but the problem is that metadata are not showed in the wallet or opensea.
This is the contract
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.17;
import '#openzeppelin/contracts/token/ERC721/ERC721.sol';
import '#openzeppelin/contracts/access/Ownable.sol';
import "#openzeppelin/contracts/utils/Counters.sol";
contract NFT is ERC721, Ownable {
uint256 public mintPrice;
uint256 public maxPerWallet;
uint256 public totalSupply;
bool public isPublicMintEnabled;
string internal baseTokenUri;
address payable public withdrawWallet;
mapping (address => uint256) public walletMints;
mapping(uint256 => string) private _tokenURIs;
Counters.Counter private _tokenIds;
using Counters for Counters.Counter;
using Strings for uint256;
constructor() payable ERC721('NFT', 'NFT') {
mintPrice = 0.0004 ether;
maxPerWallet = 3;
// Set withdraw wallet address
}
function setIsPublicMintEnabled(bool isPublicMintEnabled_) external onlyOwner {
isPublicMintEnabled = isPublicMintEnabled_;
}
function setBaseTokenUri(string calldata baseTokenUri_) external onlyOwner {
baseTokenUri = baseTokenUri_;
}
function tokenURI(uint256 tokenId_) public view override returns (string memory) {
require(_exists(tokenId_), 'Token does not exist!');
return string(abi.encodePacked(baseTokenUri, Strings.toString(tokenId_), ".json"));
}
function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual
{
_tokenURIs[tokenId] = _tokenURI;
}
function withDraw() external onlyOwner {
(bool success, ) = withdrawWallet.call{ value: address(this).balance } ('');
require(success, 'Withdraw failed');
}
function mint(string memory uri) public payable returns (uint256) {
require(isPublicMintEnabled, 'Mint is not enabled');
require(msg.value == mintPrice, 'Wrong mint value');
require(walletMints[msg.sender] + 1 <= maxPerWallet, 'Exceed max quantity per wallet');
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(msg.sender, newItemId);
_setTokenURI(newItemId, uri);
return newItemId;
}
}
And this is the mint function on the mint website
const mintNFT = async (nft) => {
setMinting(true)
const mintAmount = 1
const isConnected = Boolean(accounts[0])
if (!isConnected) {
alert('Non sei connesso al tuo Wallet')
setMinting(false)
return
}
var nftParsed = JSON.parse(nft.metadata)
if (window.ethereum) {
// Connect to blockchain
const provider = new providers.Web3Provider(window.ethereum)
const signer = provider.getSigner()
const contract = new Contract(
address,
NFT.abi, // Implement
signer
)
const imageFile = await dataUrlToFile(nftParsed.image, "img.png")
const nftstorage = new NFTStorage({ token: NFT_STORAGE_KEY })
const storage = await nftstorage.store({
image: imageFile,
name: nftParsed.name,
description: 'prova'
})
if (storage) {
try {
const response = await contract.mint(storage.url, {
value: ethers.utils.parseEther((0.0004).toString())
})
console.log(response)
} catch (e) {
console.error(e)
alert("Sorry, error while minting your NFT")
setMinting(false)
}
} else {
alert("Mint problems")
setMinting(false)
}
setMinting(false)
}
}
This code convert dataurl (format for nft saved in db) to image
async function dataUrlToFile(dataUrl, fileName) {
const res = await fetch(dataUrl);
const blob = await res.blob();
return new File([blob], fileName, { type: 'image/png' });
}
In first try, i successfully created nft with metadata, but now using a min website seems to be impossible, the time that it worked the image was stored in a directory and not in a dataurl format.
Hope someone can help,
Thanks
I try to upload an image that is created from an base64 URI.
When i want to upload the image my server response with an 400 Status and i dont find my issue...
Can someone please help me?
This is my function to generate the image:
convertDataUrlToBlob(dataUrl): Blob {
const arr = dataUrl.split(',');
const mime = arr[0].match(/:(.*?);/)[1];
const bstr = atob(arr[1]);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], {type: mime});
}
The Image Object:
ProfileImage: File
lastModified: 1603491333691
lastModifiedDate: Sat Oct 24 2020 00:15:33 GMT+0200 (Mitteleuropäische Sommerzeit) {}
name: "userprofile.png"
size: 1911552
type: "image/png"
webkitRelativePath: ""
This is my function to upload the image
onPostClick(): void {
const file = new File([this.convertDataUrlToBlob(this.imageDestination)], "userprofile.png", {type: 'image/png'});
const data = {
ProfileImage : file,
id : this.userId
}
this.errorMessage = "";
if(this.imageDestination != ""){
this.postService.post(data).subscribe(result=>{
if(result){
console.log(result)
}
},
(error:HttpErrorResponse) => {
alert(error.message);
})
}
this.dialogRef.close();
}
My controller to uploade the image:
[HttpPut]
[Authorize]
//[RequestSizeLimit(1_000_000)]
[Route("UpdateImage")]
public async Task<IActionResult> UpdateImage(ApplicationUserModel model)
{
try
{
var user = await _userManager.FindByIdAsync(model.id);
if (user.ProfileImagePath != null)
{
var file = new FileInfo(user.ProfileImagePath);
file.Delete();
}
var uniqueFileName = GetUniqueFileName(model.ProfileImage.FileName);
var uploads = Path.Combine(hostingEnvironment.WebRootPath, "Images/ProfileImages");
var filePath = Path.Combine(uploads, uniqueFileName);
await model.ProfileImage.CopyToAsync(new FileStream(filePath, FileMode.Create));
user.ProfileImagePath = filePath;
var result = await _userManager.UpdateAsync(user);
return Ok(result);
}
catch (Exception ex)
{
throw ex;
}
}
The UserModel
public class ApplicationUserModel
{
public string id { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime Birthdate { get; set; }
public DateTime EntryDate { get; set; }
public string Role { get; set; }
public IFormFile ProfileImage { get; set; }
public IFormFile HeaderImage { get; set; }
public string ProfileImagePath { get; set; }
}
Im programming in Visual Code C#, i'm making a chat application in SignalR, i want to store messages in a database in MongoDB. I need a help, that how can I use the 'message' and the 'user' variable from chat.js file in the Pogram.cs?
chat.js
"use strict";
var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build();
//Disable send button until connection is established
document.getElementById("sendButton").disabled = true;
connection.on("ReceiveMessage", function (user, message) {
var msg = message.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
var encodedMsg = user + ": " + msg;
var li = document.createElement("li");
li.textContent = encodedMsg;
document.getElementById("messagesList").appendChild(li);
});
connection.start().then(function () {
document.getElementById("sendButton").disabled = false;
}).catch(function (err) {
return console.error(err.toString());
});
document.getElementById("sendButton").addEventListener("click", function (event) {
var user = document.getElementById("userInput").value;
var message = document.getElementById("messageInput").value;
connection.invoke("SendMessage", user, message).catch(function (err) {
return console.error(err.toString());
});
event.preventDefault();
});
Program.cs
namespace bcwebchat
{
public class Message{
public DateTime Sent;
public string Msg;
}
public class Program
{
public static void Main(string[] args)
{
var client = new MongoClient("mongodb://localhost:27017");
var db = client.GetDatabase("DemoInsert");
var collec = db.GetCollection<Message>("DemoInsert");
collec.InsertOne(new Message
{
Sent = DateTime.Now,
Msg = "blaaahahaah"
});
I want to use the user and the message in here:
collec.InsertOne(new Message
{
Sent = DateTime.Now,
Msg = "blaaahahaah"
});
Just following this section Microsoft SignalR
First, you should create a ASP.NET Web Application
Then, create a ChatHub and insert message, it should work
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
{
// insert your message to database
collec.InsertOne(new Message
{
Sent = DateTime.Now,
Msg = message
});
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddSignalR();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//some code here
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapHub<ChatHub>("/chatHub");
});
}
I'm trying to bind a put request that contains File in typescript to Nancy's HttpFile. The request always sets the HttpFile in C# to null. Is there a way to do this?
#Injectable()
export class FileUploadService {
#Output() progress: EventEmitter<number> = new EventEmitter<number>();
/**
* uploads a file to the service and returns the document's id
*/
public upload(req: IUploadRequest): Observable<number> {
let promise = new Promise((resolve: any, reject: any) => {
let xhr: XMLHttpRequest = new XMLHttpRequest();
xhr.upload.onprogress = (event: any) => {
let progress = Math.round(event.lengthComputable ? event.loaded * 100 / event.total : 0);
this.progress.emit(progress);
};
xhr.onload = () => {
let json = JSON.parse(xhr.response);
resolve(<number>json.documentId);
};
xhr.onerror = () => {
reject(xhr.response);
};
xhr.onabort = () => {
reject(xhr.response);
};
xhr.open("PUT", `${environment.API_ROOT}/document`, true);
xhr.setRequestHeader(environment.AUTH_HEADER_NAME, getToken());
let formData: FormData = new FormData();
formData.append("file", <File>req.file, req.file.name);
formData.append("description", req.description);
formData.append("chapterId", req.chapterId.toString());
xhr.send(formData);
});
return Observable.fromPromise(promise);
}
}
export class IUploadRequest {
public file: File;
public description: string;
public chapterId: number;
}
The model I'm trying to bind to...
public class FileUploadRequest
{
public long ContentSize { get; set; }
public HttpFile File { get; set; }
public string Description { get; set; }
public int ChapterId { get; set; }
}
And in the C# API...
var request = this.Bind<FileUploadRequest>();
What am I doing wrong? "file" always comes back as null in C#.
Just an FYI... I fixed this by going into the request itself and grabbing the File in Request.File.