Passing and calling a function from one service to the another - c#

I wrote a function that will get and update what I need.
public async Task<bool> UpdateWellFile(IEnumerable<AttachedFileListView> files, string wellId)
{
var updateFiles = await _attachedFileRepo.GetAllQueryable().Where(af => af.WellId == wellId).ToListAsync();
if (files == null)
{
throw new ServiceException("File Not Found.");
}
foreach(var file in files)
{
var updateFile = updateFiles.SingleOrDefault(af => af.Id == file.Id);
updateFile.Category = file.Category;
_attachedFileRepo.Update(updateFile);
}
await _attachedFileRepo.CommitAsync();
return true;
}
This is in my AttachedFile Interface
public interface IAttachedFileService
{
Task<IEnumerable<AttachedFileListView>> GetWellAttachedFiles(string wellId);
Task<string> SaveFile(IFormFile file, string wellId, string userId);
Task<IEnumerable<string>> SaveFiles (IEnumerable<IFormFile> files, string wellId, string userId);
Task<bool> UpdateWellFile(IEnumerable<AttachedFileListView> files, string wellId);
Task<AttachedFile> GetFile(string fileId);
Task<string> DeleteFile(string fileId);
}
Now I need to pass this updateWellFile function into the WellService and call it so I added it to the service but it is throwing this error
here is the well service and I added the "accountservice" so I am not sure what else it needs

Related

The ReadAsync method cannot be called when another read operation is pending

I have some PDFs stored in my dropbox location and want users to be able to retrieve them via a call to an API.
[HttpGet("{key}")]
public async Task<ActionResult> GetPDF(string key) {
string? path = GetPath(key);
if (path == null) {
return NotFound();
}
using(System.Net.Http.HttpClient wc = new System.Net.Http.HttpClient()) {
try {
using(System.IO.Stream stream = await wc.GetStreamAsync(path)) {
// using(System.IO.Stream stream = wc.GetStreamAsync(path).GetAwaiter().GetResult()) {
return new FileStreamResult(stream, "application/pdf");
}
} catch(System.Exception ex) {
return NotFound();
}
}
}
It runs right through, without hitting the exception, and returns, then gives the error
The ReadAsync method cannot be called when another read operation is pending.
Waiting for the async method didn't help.
Your primary issue appears to be that the stream has been disposed before the function returns. FileStreamResult will dispose the stream, you don't need to do that.
Also, HttpClient should be a global field, otherwise you could get socket exhaustion issues.
HttpClient wc = new HttpClient();
[HttpGet("{key}")]
public async Task<ActionResult> GetPDF(string key)
{
string? path = GetPath(key);
if (path == null)
{
return NotFound();
}
try
{
var stream = await wc.GetStreamAsync(path);
return new FileStreamResult(stream, "application/pdf");
}
catch(System.Exception ex)
{
return NotFound();
}
}

How get async method value from non async method

I have async method called GetDetails(); to get data from API.
public async Task<string> GetDetails(string token, int tenantId, string fromDate,string searchText)
{
try
{
string serviceUrl = "http://localhost/Testapi/api/details/requestDetails/Details";
//API callimg code going here....
var response = await client.PostAsync(serviceUrl, content);
var result = await response.Content.ReadAsStringAsync();
client.Dispose();
return result;
}
}
I need to get above async method data. So I tried do it as follows,
public string GetAllDetails(string token, int tenantId, string fromDate,string searchText)
{
var dataResult = GetDetails(token,tenantId,fromDate,searchText);
return dataResult;
}
But I can't call GetDetails async method from non async method. Have any other way to do this? I can make that GetAllDetails() method as async, because it calling from web method as follows.
[WebMethod(EnableSession = true)]
public string GetDetails(string fromDate,string searchText)
{
try
{
SessionState session = new SessionState(Session);
DetialsConfiguration dc = new DetialsConfiguration();
string details = dc.GetAllDetails(session.JwtToken, session.ClientId,fromDate,searchText);
return details;
}
catch (Exception ex)
{
Logger.LogErrorEvent(ex);
throw;
}
}
How can I get GetDetails() API response data to my web method? Please help me to do this?
How get async method value from non async method
You don't... unless you have a very specific use case. Instead you let the async and await pattern propagate
public async Task<string> GetAllDetails(string token, int tenantId, string fromDate,string searchText)
{
var dataResult = await GetDetails(token,tenantId,fromDate,searchText);
return dataResult;
}
...
[WebMethod(EnableSession = true)]
public async Task<string> GetDetails(string fromDate,string searchText)
{
try
{
SessionState session = new SessionState(Session);
DetialsConfiguration dc = new DetialsConfiguration();
string details = await dc.GetAllDetails(session.JwtToken, session.ClientId,fromDate,searchText);
return details;
}
catch (Exception ex)
{
Logger.LogErrorEvent(ex);
throw;
}
}
Also note any async methods should have the Async Suffix E.g GetAllDetailsAsync

What pattern to use for init value

I have a service, which works with external resource (Microsoft Graph):
public class Office365DomainService : IOffice365DomainService
{
private GraphServiceClient _graphClient;
public async Task AddDomainAsync(string domain)
{
await _graphClient.Domains.Request().AddAsync(new Microsoft.Graph.Domain { Id = domain });
}
public async Task<string> GetMxRecordForDomainAsync(string domain)
{
var collection = await _graphClient.Domains[domain].ServiceConfigurationRecords.Request().GetAsync();
return String.Empty;
}
public async Task<string> GetVerificationRecordForDomainAsync(string domain)
{
var records = (await _graphClient.Domains[domain].VerificationDnsRecords.Request().GetAsync());
string verificationText = String.Empty;
foreach (var record in records)
{
if (record.RecordType == "Txt")
{
verificationText = ((Microsoft.Graph.DomainDnsTxtRecord)record).Text;
break;
}
}
return verificationText;
}
public async Task VerifyDomainAsync(string domain)
{
await _graphClient.Domains[domain].Verify().Request().PostAsync();
}
}
_graphClient should be init with access_token, but I want to have lazy loading, therefore I don't want to add it to constructor.
Ok, one solution is add a property:
public string AccessToken { set => _graphClient = (new GraphSdkHelper()).GetAuthenticatedClient(value); }
It works fine, if we remember to set AccessToken before calling any method. But if we forget to do it? The best way it is to call getting access_token by another service if this _graphClient is not init. How to do it carefully?
Why not use Lazy Initialization ?
Please take a look at the docs here

Cannot access a disposed object while using different contexts

I am trapped with definitions of Entity framework and using objects.
I am trying to save an uploaded file once I am saving the details related to that file in my database.
public async Task<IActionResult> Edit(string List<IFormFile> files, [Bind("param")] Entity entity)
{
if (ModelState.IsValid)
{
try
{
_context.Update(entity);
await _context.SaveChangesAsync();
//update Attachments
if (files.Count > 0)
{
attachment.UploadFiles(files);
}
}
catch (DbUpdateConcurrencyException)
{
if (!EntityExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction("Index");
}
return View(entity);
}
When I run the application and want to submit the form I receive below error:
Cannot access a disposed object.
Object name: 'FileBufferingReadStream'.
[HttpPost]
public async void UploadFiles(List<IFormFile> files)
{
if (files == null || files.Count == 0)
{
log.error("files not selected");
}
try
{
List<string> filenames = new List<string>();
string directory = Directory.GetCurrentDirectory() + "\\wwwroot";
createDir(directory);
foreach (var file in files)
{
string filename = file.GetFilename();
filenames.Add(filename);
}
if (filenames.Count > 0)
foreach (var filename in filenames)
{
AttachmentQ(filename, directory, createdBy);
}
foreach (var file in files)
{
string filename = file.GetFilename();
var path = Path.Combine(directory, filename);
using (var stream = new FileStream(path, FileMode.Create))
{
await file.CopyToAsync(stream);
}
filenames.Add(filename);
}
}
catch (Exception e)
{
log.error(e.Message);
}
}
[ValidateAntiForgeryToken]
public async void AttachmentQ(string filename, string path, string createdBy)
{
try
{
Attachment attachment = new Attachment
{
Name = filename,
Path = path,
CreatedBy = createdBy,
CreatedDate = DateTime.Now
};
_context.Add(attachment);
await _context.SaveChangesAsync();
}
catch (Exception e)
{
log.error(e.Message);
}
}
Surprisingly I don't get error in debug mode. But when I run the app I get This page isn’t working error.
I also noticed I need to return a value when I use async but I don't have any return vale in UploadFiles() and AttachmentQ() methods.
Could you please help me how to handle objects when using different contexts. Thanks
Do NOT use async void at all.
if you want to use async/await pattern then let your methods returns Task
public async Task UploadFiles(List<IFormFile> files)

Call a controller action asynchronously in MVC

I have a Controller in my MVC 5 application as follows;
public class DownloadController : Controller
{
public FileContentResult CsvDownload(string fileName)
{
byte[] data = GetCSVData(fileName);
return File(data, "text/csv", fileName);
}
}
I have some other Actions in the DownloadController as well. I want to convert the CsvDownload File result to an async Task, because sometimes the data can take time to process. How can I run the CsvDownload function asynchronously so that it does not block the main thread. At times it takes about 2 to 4 minutes to download data.
What is the preferred solution to running a method on a separate thread while in the same controller.
EDIT
I was searching for a solution when I came across the following:
http://blog.newslacker.net/2013/03/aspnet-mvc-how-to-make-working-progress.html
If I can get a solution of something like the following:
public delegate string GetCsvDataCaller(string fileName);
public string GetCsvData(string fileName)
{
string file = "filename.csv";
//Get CSV Data
return file;
}
public JsonResult StartExporting(string fileName)
{
var caller = new GetCsvDataCaller(GetCsvData);
caller.BeginInvoke(fileName, GetCsvCallBack, null);
return Json(new { Status = "started" }, JsonRequestBehavior.DenyGet);
}
public JsonResult GetCsvCallBack(IAsyncResult ar)
{
AsyncResult result = (AsyncResult) ar;
AsyncMethodCaller caller = (AsyncMethodCaller) result.AsyncDelegate;
string returnValue = caller.EndInvoke();
return Json(new { FileName = returnValue }, JsonRequestBehavior.DenyGet);
}
Is this possible in ASP.NET MVC?
public class DownloadController : Controller
{
[HttpPost]
public async Task<ActionResult> CsvDownload(string fileName)
{
byte[] data = await Task.Run(() => GetCSVData(fileName));
return File(data, "text/csv", fileName);
}
}

Categories

Resources