The purpose of this project is to demonstrate interoperability of the Cloudinary Upload Widget, a complete, interacive user interface that allows your users to upload a variety of sources to your website or application.
- Have a Cloudinary account.
- Configure an unsigned Upload Preset
- set up the following secret keys:
dotnet user-secrets set "CloudinaryConfig:Cloud" "<your-cloud-name>"
dotnet user-secrets set "CloudinaryConfig:APIKey" "<apikey>"
dotnet user-secrets set "CloudinaryConfig:APISecret" "<apiSecret>"
dotnet user-secrets set handle "<folderName>"
dotnet user-secrets set "preset" "<cloudinaryPreset>" #the upload preset name
In this demo, the folder value is used for the images and is part of the image's public id.
Add the Cloudinary widget script reference either above or below the Blazor script reference.
<script src="https://upload-widget.cloudinary.com/global/all.js"></script>
<script src="_framework/blazor.server.js"></script>
This Javascript file sets up and fires off our widget from our code.
IMPORTANT
Do not reference the Cloudinary JS library from your code by using an import
statement - you will get CORS issues and have a bad time.
We create three methods:
setCloudinaryCloudName
to set the cloud name for CloudinarysetupCloudinaryUploadWidget
which configures the widgetopenWidget
which opens the widget
setCloudinaryCloudName
can be replaced by simply passing in the cloud name as a parameter to setupCloudinaryUploadWidget
but it's just a matter of preference - either way is sufficient.
In setupCloudinaryUploadWidget
we pass in a couple of parameters, most notably of which is a DotNetObjectReference we use for invoking a method in our Blazor page in the widget event. We also pass in the name of the method so we can invoke it.
In our demo, this page does all the work.
First thing we do is set up a button that calls a method.
@page "/"
@using EPS.Demos.BlazorCloudinary.Models
@using Microsoft.Extensions.Configuration
@using Newtonsoft.Json
@inject IJSRuntime JS
@inject Cloudinary cloudinary
@inject IConfiguration config
<h1>Cloudinary demo</h1>
<div class="row">
<div class="col-1">
<button class="btn-lg" @onclick="LoadFile">Upload Image</button>
</div>
</div>
@if (SuccessEvent is not null)
{
<div class="row">
@imgString
</div>
}
In the OnAfterRenderAsync event, we do the following:
- set up a IJSObjectReference to our javascript file that manages our Cloudinary widget
- read some config settings
- invoke
setCloudinaryCloudName
and set our cloud name - invoke
setupCloudinaryUploadWidget
with our parameters, including a DotNetObjectReference toIndex
with the name of the method to invoke (UploadComplete
)
The code looks like this:
private IJSObjectReference module;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./js/imgHandler.js");
var preset = config["preset"];
var handle = config["handle"];
var cloud = config["CloudinaryConfig:Cloud"];
await module.InvokeVoidAsync("setCloudinaryCloudName", cloud);
//pass in
await module.InvokeVoidAsync("setupCloudinaryUploadWidget",preset,handle,
DotNetObjectReference.Create(this),"UploadComplete").ConfigureAwait(false);
}
}
Our button in the UI code is wired to a method that invokes the openWidget
method.
private async Task LoadFile()
{
Console.WriteLine("invoking LoadFile");
await module.InvokeVoidAsync("openWidget");
}
When the widget uploads successfully, it closes and invokes our callback. In the demo, we use the Cloudinary SDK to generate a <img>
tag for us, which is a bit redundant in this case since we have a number of URLs to pick from. But what better time to remind ourselves that you need to use a MarkupString in order to display raw HTML in a Blazor UI!
[JSInvokable]
public void UploadComplete(string response)
{
Console.WriteLine(response);
SuccessEvent = JsonConvert.DeserializeObject<SuccessEvent>(response);
imgString = new MarkupString(cloudinary.Api.UrlImgUp.BuildImageTag(SuccessEvent.info.public_id));
StateHasChanged();
}
- 'Live Broadcast' should be turned off in youir upload presets if you plan on capturing camera inputs for uploading pictures.
- Watch for typos in your method names - this includes capitalization. As obvious as that sounds, a simple 'CLoudinary' method name misspelling gave me at least a good hour of headaches. Don't let it happen to you!