Sensenet: Upload Files through Sensenet Client API and Set Modified User - sensenet

I have a requirement that consists on uploading files through other system to sensenet.
I'm trying to use the Sensenet Client API to upload files but I'm having difficult using the examples documented on the follow links:
Client Library (the code runs well but the file doesn't appear on Sensenet)
Common API Calls (I'm having trouble to compile the code... to instantiate the BinaryData object)
Beside this, I need for each uploading file define the "Modified By" that I specify in my code and not the user that I use to authenticate me in the API.

I think rewriting the ModifiedBy field is an edge case (or a small hack) but it is possible without any magic (see the code). The easiest way is a POST followed by a PATCH, that is perfectly managed by the SenseNet.Client (the code uses a local demo site):
static void Main(string[] args)
{
ClientContext.Initialize(new[]
{new ServerContext {Url = "http://localhost", Username = "admin", Password = "admin"}});
var localFilePath = #"D:\Projects\ConsoleApplication70\TestFileFromConsole1.txt";
var parentPath = "/Root/Sites/Default_Site/workspaces/Document/londondocumentworkspace/Document_Library";
var fileName = "TestFileFromConsole1.txt";
var path = parentPath + "/" + fileName;
var userPath = "/Root/IMS/BuiltIn/Demo/ProjectManagers/alba";
using (var stream = new FileStream(localFilePath, FileMode.Open))
Content.UploadAsync(parentPath, fileName, stream).Wait();
Console.WriteLine("Uploaded");
Modify(path, userPath).Wait();
Console.WriteLine("Modified");
Console.Write("Press <enter> to exit...");
Console.ReadLine();
}
// Rewrites the ModifiedBy field
private static async Task Modify(string path, string userPath)
{
var content = await Content.LoadAsync(path);
content["ModifiedBy"] = userPath;
await content.SaveAsync();
}

Related

Easy way to retrieve image source in abp

I'm pretty new to ABP Framework and probably this question has a really simple answer, but I haven't managed to find it. Images are an important part of any app and handling them the best way (size, caching) is mandatory.
Scenario
setup a File System Blob Storing provider. This means that the upload file will be stored in the file system as an image file
make a service that uses a Blob container to save and retrieve the image. So, after saving it, I use the unique file name as a blob name. This name is used to retrieve it back.
the user is logged in, so authorization is required
I can easily obtain the byte[]s of the image by calling blobContainer.GetAllBytesOrNullAsync(blobName)
I want to easily display the image in <img> or in datatable row directly.
So, here is my question: is there an easy way to use a blob stored image as src of a <img> directly in a razor page? What I've managed to achieve is setting in the model, a source as a string made from image type + bytes converted to base 64 string (as here) however in this case I need to do it in the model and also I don't know if caching is used by the browser. I don't see how caching would work in this case.
I am aware that this may be a question more related to asp.net core, but I was thinking that maybe in abp there is some way via a link to access the image.
If you have the ID of the blob then it is easy to do. Just create a Endpoint to get the Image based on the blob id.
Here is the sample AppService
public class DocumentAppService : FileUploadAppService
{
private readonly IBlobContainer<DocumentContainer> _blobContainer;
private readonly IRepository<Document, Guid> _repository;
public DocumentAppService(IRepository<Document, Guid> repository, IBlobContainer<DocumentContainer> blobContainer)
{
_repository = repository;
_blobContainer = blobContainer;
}
public async Task<List<DocumentDto>> Upload([FromForm] List<IFormFile> files)
{
var output = new List<DocumentDto>();
foreach (var file in files)
{
using var memoryStream = new MemoryStream();
await file.CopyToAsync(memoryStream).ConfigureAwait(false);
var id = Guid.NewGuid();
var newFile = new Document(id, file.Length, file.ContentType, CurrentTenant.Id);
var created = await _repository.InsertAsync(newFile);
await _blobContainer.SaveAsync(id.ToString(), memoryStream.ToArray()).ConfigureAwait(false);
output.Add(ObjectMapper.Map<Document, DocumentDto>(newFile));
}
return output;
}
public async Task<FileResult> Get(Guid id)
{
var currentFile = _repository.FirstOrDefault(x => x.Id == id);
if (currentFile != null)
{
var myfile = await _blobContainer.GetAllBytesOrNullAsync(id.ToString());
return new FileContentResult(myfile, currentFile.MimeType);
}
throw new FileNotFoundException();
}
}
Upload function will upload the files and Get function will get the file.
Now set the Get route as a src for the image.
Here is the blog post: https://blog.antosubash.com/posts/dotnet-file-upload-with-abp
Repo: https://github.com/antosubash/FileUpload

non-invocable member 'File' cannot be used like a method error message- what am I missing?

I have a Blazor Application which had files uploaded to a upload folder on the web server. I am in the process of trying to figure out the code to download an uploaded file in the browser for retrieval and viewing. Right now the code is as below (the download part from code examples on the internet)
public void FileDetailsToolbarClickHandler(Syncfusion.Blazor.Navigations.ClickEventArgs args)
{
string path = null;
string uploads = System.IO.Path.Combine(System.IO.Directory.GetCurrentDirectory(), "wwwroot\\uploads");
path = uploads + "\\" + SelectedFileName;
if (args.Item.Text == "Delete")
{
//Code for Deleting goes here
//UploadRef.Remove();
if (System.IO.File.Exists(path))
{
System.IO.File.Delete(path);
}
FileDetailsService.FileDetailsDelete(SelectedFileId); //NavigationManager.NavigateTo($"/ServiceRequestNotes/servicerequestnoteadd");
NavigationManager.NavigateTo($"/ServiceRequests/serviceRequestsaddedit2/{Id}", forceLoad: true);
}
else
{
// its a download
IFileProvider provider = new PhysicalFileProvider(uploads);
IFileInfo fileinfo = provider.GetFileInfo(path + SelectedFileName);
var readStream = fileinfo.CreateReadStream();
var mimeType = "application/pdf";
return File(readStream, mimeType, SelectedFileName);
}
}
On the last statement I am a getting the following error message
non-invocable member 'File' cannot be used like a method error message
What am I missing or do I need to change or add to have the output from the readstream render to the browser?
The blazor application is a blazor server app not WASM. It does not make use of API controllers.
Any advice?
This is a void method. You can't return anything at all. Also, if you're trying to instantiate a File object, you'd have to use the new keyword.

Power App - generate PDF

I got an assignment to see if I can make power app that will generate some PDF file for end user to see.
After through research on this topic I found out that this is not an easy to achieve :)
In order to make power app generate and download/show generated pdf I made these steps:
Created power app with just one button :) to call Azure function from step 2
Created Azure function that will generate and return pdf as StreamContent
Due to power app limitations (or I just could not find the way) there was no way for me to get pdf from response inside power app.
After this, I changed my Azure function to create new blob entry but know I have problem to get URL for that new entry inside Azure function in order to return this to power app and then use inside power app Download function
My Azure function code is below
using System;
using System.Net;
using System.Net.Http.Headers;
using System.Runtime.InteropServices;
using Aspose.Words;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log, Stream outputBlob)
{
log.Info($"C# HTTP trigger function processed a request. RequestUri={req.RequestUri}");
var dataDir = #"D:/home";
var docFile = $"{dataDir}/word-templates/WordAutomationTest.docx";
var uid = Guid.NewGuid().ToString().Replace("-", "");
var pdfFile = $"{dataDir}/pdf-export/WordAutomationTest_{uid}.pdf";
var doc = new Document(docFile);
doc.Save(pdfFile);
var result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new FileStream(pdfFile, FileMode.Open);
stream.CopyTo(outputBlob);
// result.Content = new StreamContent(stream);
// result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
// result.Content.Headers.ContentDisposition.FileName = Path.GetFileName(pdfFile);
// result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
// result.Content.Headers.ContentLength = stream.Length;
return result;
}
I left old code (the one that streams pdf back under comments just as reference of what I tried)
Is there any way to get download URL for newly generated blob entry inside Azure function?
Is there any better way to make power app generate and download/show generated PDF?
P.S. I tried to use PDFViewer control inside power app, but this control is completely useless cause U can not set Document value via function
EDIT: Response from #mathewc helped me a lot to finally wrap this up. All details are below.
New Azure function that works as expected
#r "Microsoft.WindowsAzure.Storage"
using System;
using System.Net;
using System.Net.Http.Headers;
using System.Runtime.InteropServices;
using Aspose.Words;
using Microsoft.WindowsAzure.Storage.Blob;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log, CloudBlockBlob outputBlob)
{
log.Info($"C# HTTP trigger function processed a request. RequestUri={req.RequestUri}");
var dataDir = #"D:/home";
var docFile = $"{dataDir}/word-templates/WordAutomationTest.docx";
var uid = Guid.NewGuid().ToString().Replace("-", "");
var pdfFile = $"{dataDir}/pdf-export/WordAutomationTest_{uid}.pdf";
var doc = new Document(docFile);
doc.Save(pdfFile);
var result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new FileStream(pdfFile, FileMode.Open);
outputBlob.UploadFromStream(stream);
return req.CreateResponse(HttpStatusCode.OK, outputBlob.Uri);
}
REMARKS:
Wee need to add "WindowsAzure.Storage" : "7.2.1" inside project.json. This package MUST be the same version as one with same name that is in %USERPROFILE%\AppData\Local\Azure.Functions.Cli
If you change your blob output binding type from Stream to CloudBlockBlob you will have access to CloudBlockBlob.Uri which is the blob path you require (documentation here). You can then return that Uri back to your Power App. You can use CloudBlockBlob.UploadFromStreamAsync to upload your PDF Stream to the blob.

Cascading Tap Configuration for Amazon S3 to Local file System

So I'm trying out the cascading framework and I was able to run apps in local. As a next step I want to use Cascading to download files from S3 to local file system. I'm planning to use FileTap. When I google I found S3FS and looks like its deprecated. Can someone point me in the right direction. In other words, what is the right way to create a FileTap for Amazon S3 with access id and secret key like stuff.
Though this code is for the HadoopFlowConnector this will work with Local Flow connector if using the FileTap.
public class Main {
public void run(String[] args) {
Properties properties = new Properties();
String accessKey = args[0];
String secretKey = args[1];
// better put these keys to hadoop xml file
// for block file system
properties.setProperty("fs.s3.awsAccessKeyId", accessKey);
properties.setProperty("fs.s3.awsSecretAccessKey", secretKey);
// for s3 native file system
// properties.setProperty("fs.s3n.awsAccessKeyId", accessKey);
// properties.setProperty("fs.s3n.awsSecretAccessKey", secretKey);
// properties.setProperty("fs.defaultFS", "hdfs://localhost:8020/");
// properties.setProperty("fs.permissions.umask-mode", "007");
AppProps.setApplicationJarClass(properties, Main.class);
HadoopFlowConnector flowConnector = new HadoopFlowConnector(
properties);
String input = "s3://my-bucket/my-log.csv";
// If using the native S3
// String input = "s3n://my-bucket/my-log.csv";
Tap inTap = new Hfs(new TextDelimited(false, ";"), input);
Pipe copyPipe = new Pipe("copy");
Tap outTap = new Hfs(new TextDelimited(false, ";"),
"data/output");
FlowDef flowDef = FlowDef.flowDef()
.addSource(copyPipe, inTap)
.addTailSink(copyPipe, outTap);
flowConnector.connect(flowDef).complete();
}
public static void main(String[] args) {
new Main().run(args);
}
}
Code courtesy http://whiteboxdeveloper.blogspot.com/2015/01/processing-data-from-aws-s3-using.html.
I just added the S3N string input commented line. Since I was using S3N based accessing I uncommented the S3N features and used it.

How do I open a file when clicking an ActionLink?

How do I open an existing file on the server when a user clicks an actionlink? The following code works for downloading a file but I want to open a new browser window, or tab, and display the file contents.
public ActionResult Download()
{
return File(#"~\Files\output.txt", "application/text", "blahblahblah.txt");
}
You must add "inline" for a new tab.
byte[] fileBytes = System.IO.File.ReadAllBytes(contentDetailInfo.ContentFilePath);
Response.AppendHeader("Content-Disposition", "inline; filename=" + contentDetailInfo.ContentFileName);
return File(fileBytes, contentDetailInfo.ContentFileMimeType);
The way you're using the File() method is to specify a file name in the third argument, which results in a content-disposition header being sent to the client. This header is what tells a web browser that the response is a file to be saved (and suggests a name to save it). A browser can override this behavior, but that's not controllable from the server.
One thing you can try is to not specify a file name:
return File(#"~\Files\output.txt", "application/text");
The response is still a file, and ultimately it's still up to the browser what to do with it. (Again, not controllable from the server.) Technically there's no such thing as a "file" in HTTP, it's just headers and content in the response. By omitting a suggested file name, the framework in this case may omit the content-disposition header, which is your desired outcome. It's worth testing the result in your browser to see if the header is actually omitted.
Use a target of blank on your link to open it in a new window or tab:
Download File
However, forcing the browser to display the contents is out of your control, as it entirely depends on how the user has configured their browser to deal with files that are application/text.
If you are dealing with text, you can create a view and populate the text on that view, which is then returned to the user as a regular HTML page.
please try this and replace your controller name and action name in html action link
public ActionResult ShowFileInNewTab()
{
using (var client = new WebClient()) //this is to open new webclient with specifice file
{
var buffer = client.DownloadData("~\Files\output.txt");
return File(buffer, "application/text");
}
}
OR
public ActionResult ShowFileInNewTab()
{
var buffer = "~\Files\output.txt"; //bytes form this
return File(buffer, "application/text");
}
this is action link which show in new blank tab
<%=Html.ActionLink("Open File in New Tab", "ShowFileInNewTab","ControllerName", new { target = "_blank" })%>
I canĀ“t vote your answered as is useful, follow dow. Thanks very much !
public FileResult Downloads(string file)
{
string diretorio = Server.MapPath("~/Docs");
var ext = ".pdf";
file = file + extensao;
var arquivo = Path.Combine(diretorio, file);
var contentType = "application/pdf";
using (var client = new WebClient())
{
var buffer = client.DownloadData(arquivo);
return File(buffer, contentType);
}
}