Multithreading accepts value and return value - asp.net

Hi guys, I wrote the following code to return a pdf report. The code is based on a multi-threading sample code. Can you guys provide some feedback about it, I am new to mulit-thread.
Much appriciate !
Jeffery
public delegate void StreamResultDelegate(Stream streamResults);
public class GenerateReport
{
private StreamResultDelegate callback;
public GenerateReport(StreamResultDelegate _callback)
{
callback = _callback;
}
public void ThreadProc()
{
if (callback != null)
{
callback(Testing());
}
}
public Stream Testing()
{
var reportsService = new ReportsService();
var nameValueCollection = new NameValueCollection();
byte[] pdfReportContents = reportsService.GetReport("/Rocket.Reports/RocketReport", nameValueCollection);
var stream = new MemoryStream(pdfReportContents);
return stream;
}
}
//following
[HandleError]
public class HomeController : Controller
{
private Stream streamTesting = null;
public void StreamResultCallBack(Stream s)
{
streamTesting = s;
}
public FileStreamResult GeneratePdfReport()
{
var g = new GenerateReport(_callback: new StreamResultDelegate(StreamResultCallBack));
var t = new Thread(new ThreadStart(g.ThreadProc));
t.Start();
t.Join();
HttpContext.Response.AddHeader("content-disposition", "attachment; filename=Rockets_List_Printout.pdf");
return new FileStreamResult(streamTesting, "application/pdf");
}}

I would suggest to use async controllers -> MSDN and stop using threads in controller methods=)

My suggestion is make a private object to store the result. It's the easiest way
update
public delegate void work_handler(Stream streamResults);
public class Report
{
public object Result = null;
private Thread workThread = new ...;
public void Work(object param)
{
this.Result = ....;
// signal finish. eg. if winapp use someControl.Invoke(signal_Handler);
// for web app use this.Session["isDone"] = true;
}
// for .net 4.0
private object param = null;
public void Work()
{
// for serial invoking
var taskOption = System.Threading.Tasks.TaskCreationOptions.LongRunning;
System.Threading.Tasks.Task task = new System.Threading.Tasks.Task(() => {... }, taskOption);
// for multiple method parallel invoke
System.Threading.Tasks.Parallel.Invoke(() => { this.Result = genReport(param); }, () => {... }, () => {...});
}
}

Related

Task was canceled but the process continued

I am processing a set of records (batch) based on a ID.
Based on exception, I am collecting exception details and sending an email.
However recently I got a “A Task was canceled” exception, so this information was added and sent in an email. But even after the exception, the record made it to the database. There were other exception and those records didn't make it to the database.
This only happens sporadically. Most of the times the exception and the records getting into the database matches.
I am using Autofac.
To give an idea
internal class Program
{
public static void Main ( )
{
IContainer context = Program.BuildContainer( );
try{
context.Resolve<IBatchProvider>().DoAsynBatchProcess().Wait();
}
catch(Exception ex)
{
//log errors
}
}
private static IContainer BuildContainer( )
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<LogBuilder>.As<ILogBuilder>().InstancePerDependency();
builder.RegisterType<EmailSender>.As<IEmailSender>().InstancePerDependency();
builder.RegisterType<BatchProvider>As<IBatchProvider>().InstancePerDependency();
return builder.Build();
}
}
public class BatchProvider : IBatchProvider {
private readonly ILogBuilder _logBulider;
private readonly IEmailsender _emailSender;
public BatchProvider(ILogBuilder logBuilder, IEmailSender emailSender)
{
_logBuilder = logBuilder;
_emailSender = emailSender;
}
public async Task DoAsyncBatchProcess()
{
//Get ID from DB
….
await BatchProcessing (ID)
}
public async Task BatchProcessing (int ID)
{
//Get all records for this ID
//loop through the records and post it.
for (int index=0; i< dataRowArray.Length; ++ index)
{
try{
bool result = await ServiceClient.PostData(guid)
}
catch(Exception ex)
{
//log exception
}
finally
{
//log to file
}
}
await SendEmail ( )
}
private async Task SendEmail()
{
//email
}
private void LogToFile()
{ //log to file
}
}
public class ServiceClient
{
public static async Task<bool> PostData(string guid)
{
using( var client = new HttpClient(new HttpClientHandler() {useDefaultCredentials = true}))
{
string _baseAddress = “http://Mywebserver/“;
client.baseAddress = new Uri(_baseAddress)
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(“application/json”);
string _method = “MyMethod”;
HttpResponseMessage response = await client.PostAsJsonAsync(_method, new ServiceRequest() {MyGuid = guid}).configureAwait(false);
if(response.IsSuccessStausCode)
{
var result = await response.Content.ReadAsAsync<ServiceResponse>();
return result.Status;
}
else
{
string message = await _response.Content.ReadAsStringAsync();
throw new Exception(message);
}
}
}
}
In my Main method does the .wait() is enough or should I do the following
Context.Resolve().DoAsyncBatchProcess().ConfigureAwait(false).GetAwaiter().GetResult();
Is there a way to ensure that the exception happen and it doesn't continue for that task but continue for the other tasks?
Thank you.

Cannot access a disposed object. with SignalR and Timer Manager

I wanna make my function send data as a real time (every 2 seconds or once there is change in the database table ) but the problem is there is Exception keep appread in my below code.
The exception details are:
'Cannot access a disposed object.
public class MyHub : Hub
{
private readonly IRepository<MyTable, long> _repository;
private readonly IUnitOfWorkManager _unitOfWorkManager;
public HCHub(IUnitOfWorkManager unitOfWorkManager,IRepository<MyTable, long> repository)
{
_repository = repository;
_unitOfWorkManager = unitOfWorkManager;
}
public void Get(TestDto testDto)
{
try {
using (var unitOfWork = _unitOfWorkManager.Begin())
{
var result= _repository.GetDbContext().Set<MyTable>()
.Include(x => x.list)
.ThenInclude(x => x.list2)
.ThenInclude(x => x.obj).ToList();
new TimerManager(async () =>
await Clients.All.SendAsync("listen", result) //<====== in this Line the exception occured
);
}
}
catch(Exception ex)
{
throw new UserFriendlyException(ex.InnerException.Message.ToString());
}
}
and TimerManager Code is
public class TimerManager
{
private Timer _timer;
private AutoResetEvent _autoResetEvent;
private Action _action;
public DateTime TimerStarted { get; }
public TimerManager(Action action)
{
_action = action;
_autoResetEvent = new AutoResetEvent(false);
_timer = new Timer(Execute, _autoResetEvent, 1000, 2000);
TimerStarted = DateTime.Now;
}
public void Execute(object stateInfo)
{
_action();
if ((DateTime.Now - TimerStarted).Seconds > 60)
{
_timer.Dispose();
}
}
}
So the problem is in Timer Manager or in myHub or the way that I'm simulate the realtime data by TimerManager is not acceptable ?!
Once you exit the hub method you aren't guaranteed to be able to access the Clients property. If you want to do something like that, you should inject an IHubContext<THub> into your Hubs constructor and use that instead. You can read more about IHubContext in https://learn.microsoft.com/aspnet/core/signalr/hubcontext?view=aspnetcore-3.1#get-an-instance-of-ihubcontext

Use torch while scanning barcode

I'm using ZXing.Mobile.Forms to scan the barcodes.
I would like to turn the torch on while scanning the barcodes. I tried ToggleTorch() but i dont see the torch light.
Please help to overcome this scenario.
Here is my code:
var scanner = new ZXing.Mobile.MobileBarcodeScanner();
scanner.ToggleTorch();
var option = new ZXing.Mobile.MobileBarcodeScanningOptions { UseCode39ExtendedMode = true, TryHarder = true, PureBarcode = true, };
var result = await scanner.Scan(option);
if (result != null)
await Application.Current.MainPage.DisplayAlert(title, result.Text, "Cancel");
await Application.Current.MainPage.Navigation.PopAsync(true);
OK here is the main idea which does what you want, in an MVVM manner:
XAML:
<zxing:ZXingScannerView x:Name="ScannerView"
IsTorchOn="{Binding IsTorchOn}"
IsScanning="{Binding IsScanning}"
IsAnalyzing="{Binding IsAnalyzing}"
ScanResultCommand="{Binding OnScanResult}"/>
Code-behind:
public partial class BarcodeScannerPage
{
private BarcodeScannerPageModel _pageModel;
public BarcodeScannerPage()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
if(_pageModel == null) return;
_pageModel.IsScanning = true;
_pageModel.IsAnalyzing = true;
_pageModel.IsTorchOn= true;
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
_pageModel = BindingContext as BarcodeScannerPageModel;
}
}
Page model:
public class BarcodeScannerPageModel
{
#region instance variables
private bool _isScanning;
private bool _isAnalyzing;
private bool _isTorchOn;
#endregion
public BarcodeScannerPageModel()
{
IsTorchOn = true;
}
public bool IsScanning
{
get => _isScanning;
set
{
_isScanning = value;
RaisePropertyChanged();
}
}
public bool IsAnalyzing
{
get => _isAnalyzing;
set
{
_isAnalyzing = value;
RaisePropertyChanged();
}
}
public ICommand OnScanResult
{
get
{
return new Command(async (result) =>
{
if (result.ToString().IsNullOrEmpty()) return;
Device.BeginInvokeOnMainThread(async () =>
{
IsAnalyzing = false;
//your code here...
});
});
}
}
public bool IsTorchOn
{
get => _isTorchOn;
set
{
_isTorchOn = value;
RaisePropertyChanged();
}
}
}
Here I assumed MVVM is set and used correctly including "PropertyChanged" events and setting "BindingContext". More info:
MVVM
From Data Bindings to MVVM
MVVM & Data Binding with Xamarin.Forms
Using some MVVM frameworks such as FreshMvvm can make things easier.

Use asyn method for synchronous Sqlite on createMethod

I'm using Xamarin, also my SQLite tables contain a large amount of data.
Because I want to avoid UIThread problems in OnCreate(), I need to perform database actions asynchronously.
I'm looking for guidance if I am handling this properly.
First method, which I found on the net:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.InventoryPreviewMain);
Thread thread = new Thread(() =>
{
SQLiteConnection db = new SQLiteConnection(dpPath);
var table = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass where CategoryID =" + Connection.CategoryID + "");
mItems = new List<InventoryPreviewClass>();
foreach (var item in table)
{
mItems.Add(new InventoryPreviewClass() { InventoryItemID = item.InventoryItemID, InventoryItemName = item.InventoryItemName, InventoryItemPrice = item.InventoryItemPrice });
}
MyListViewAdapterInventory adapter = new MyListViewAdapterInventory(this, Resource.Layout.InventoryPreview, mItems);
mlistview.Adapter = adapter;
});
thread.Start();
Second Method, using async
public async void StartTimer()
{
SQLiteConnection db = new SQLiteConnection(dpPath);
var table = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass where CategoryID =" + Connection.CategoryID + "");
mItems = new List<InventoryPreviewClass>();
foreach (var item in table)
{
mItems.Add(new InventoryPreviewClass() { InventoryItemID = item.InventoryItemID, InventoryItemName = item.InventoryItemName, InventoryItemPrice = item.InventoryItemPrice });
}
MyListViewAdapterInventory adapter = new MyListViewAdapterInventory(this, Resource.Layout.InventoryPreview, mItems);
mlistview.Adapter = adapter;
await Task.Delay(500);
}
Which of two examples are more safe for keeping alive UIthread? Is there any other solution for making this?What is more reccomended to do?
Answer
Use the Cross-platform SQLite Library made by #FrankKruger to create/access SQLite databases for Xamarin mobile apps.
This library has a built-in asynchronous connection, so you'll never need to worry about accessing the database from the UI Thread again!
Xamarin.Android Example
"Second Method"
public async Task StartTimer()
{
mItems = await InventoryPreviewClassDatabase.GetAllInventoryPreviewClassAsync();
MyListViewAdapterInventory adapter = new MyListViewAdapterInventory(this, Resource.Layout.InventoryPreview, mItems);
mlistview.Adapter = adapter;
}
BaseDatabase Class
using System;
using System.Threading.Tasks;
using SQLite;
namespace SampleApp
{
public abstract class BaseDatabase
{
#region Constant Fields
static readonly Lazy<SQLiteAsyncConnection> _databaseConnectionHolder = new Lazy<SQLiteAsyncConnection>(() => GetDatabaseConnection());
#endregion
#region Fields
static bool _isInitialized;
#endregion
#region Properties
static SQLiteAsyncConnection DatabaseConnection => _databaseConnectionHolder.Value;
#endregion
#region Methods
protected static async Task<SQLiteAsyncConnection> GetDatabaseConnectionAsync()
{
if (!_isInitialized)
await Initialize().ConfigureAwait(false);
return DatabaseConnection;
}
static async Task Initialize()
{
await DatabaseConnection.CreateTableAsync<InventoryPreviewClass>().ConfigureAwait(false);
_isInitialized = true;
}
SQLiteAsyncConnection GetDatabaseConnection()
{
var sqliteFilename = "YourDatabaseName.db3";
string documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal); // Documents folder
var path = Path.Combine(documentsPath, sqliteFilename);
var conn = new SQLiteAsyncConnection(path, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create | SQLiteOpenFlags.SharedCache);
return conn;
}
#endregion
}
}
Parent Database Class
using System.Linq;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace SampleApp
{
public abstract class InventoryPreviewClassDatabase : BaseDatabase
{
#region Methods
public static async Task<IList<InventoryPreviewClass>> GetAllInventoryPreviewClassAsync()
{
var databaseConnection = await GetDatabaseConnectionAsync().ConfigureAwait(false);
return await databaseConnection.Table<InventoryPreviewClass>().ToListAsync().ConfigureAwait(false);
}
public static async Task<InventoryPreviewClass> GetInventoryPreviewClassByIDAsync(int id)
{
var databaseConnection = await GetDatabaseConnectionAsync().ConfigureAwait(false);
return await databaseConnection.Table<InventoryPreviewClass>().Where(x => x.ID.Equals(id)).FirstOrDefaultAsync().ConfigureAwait(false);
}
public static async Task<int> SaveInventoryPreviewClassAsync(InventoryPreviewClass inventoryPreview)
{
var databaseConnection = await GetDatabaseConnectionAsync().ConfigureAwait(false);
var isObjectInDatabase = await GetInventoryPreviewClassByIDAsync(inventoryPreview.ID).ConfigureAwait(false) != null;
if (isObjectInDatabase)
return await databaseConnection.UpdateAsync(inventoryPreview).ConfigureAwait(false);
return await databaseConnection.InsertAsync(inventoryPreview).ConfigureAwait(false);
}
public static async Task<int> DeleteItemAsync(OpportunityModel opportunity)
{
var databaseConnection = await GetDatabaseConnectionAsync().ConfigureAwait(false);
return await databaseConnection.DeleteAsync(opportunity).ConfigureAwait(false);
}
public static async Task<int> GetNumberOfRowsAsync()
{
var databaseConnection = await GetDatabaseConnectionAsync().ConfigureAwait(false);
return await databaseConnection.Table<InventoryPreviewClass>().CountAsync().ConfigureAwait(false);
}
#endregion
}
}
This code was inspired from this Xamarin.Forms sample app

How do you mock ServiceStack ISession using Moq and StructureMap?

I'm using ServiceStack / StructureMap / Moq. The service makes a call to Session, which is type ServiceStack.CacheAccess.ISession. For unit tests, I created a Mock object using Moq, and added it to the StructureMap configuration:
protected Mock<ISession> sessionMock = new Mock<ISession>();
ObjectFactory.Configure(
cfg =>
{
cfg.For<ISession>().Use(sessionMock.Object);
However, I was not surprised when the Session object was null -- I'm pretty sure I'm leaving out a step. What else do I need to do to fill my Session property with a mock object?
[EDIT] Here's a simple test scenario
Code to test. Simple request / service
[Route("getKey/{key}")]
public class MyRequest:IReturn<string>
{
public string Key { get; set; }
}
public class MyService:Service
{
public string Get(MyRequest request)
{
return (string) Session[request.Key];
}
}
The base test class and MockSession classes
// test base class
public abstract class MyTestBase : TestBase
{
protected IRestClient Client { get; set; }
protected override void Configure(Container container)
{
// this code is never reached under any of my scenarios below
container.Adapter = new StructureMapContainerAdapter();
ObjectFactory.Initialize(
cfg =>
{
cfg.For<ISession>().Singleton().Use<MockSession>();
});
}
}
public class MockSession : ISession
{
private Dictionary<string, object> m_SessionStorage = new Dictionary<string, object>();
public void Set<T>(string key, T value)
{
m_SessionStorage[key] = value;
}
public T Get<T>(string key)
{
return (T)m_SessionStorage[key];
}
public object this[string key]
{
get { return m_SessionStorage[key]; }
set { m_SessionStorage[key] = value; }
}
}
And tests. See comments for where I'm seeing the failure. I didn't really expect versions 1 & 2 to work, but hoped version 3 would.
[TestFixture]
public class When_getting_a_session_value:MyTestBase
{
[Test]
public void Test_version_1()
{
var session = ObjectFactory.GetInstance<MockSession>();
session["key1"] = "Test";
var request = new MyRequest {Key = "key1"};
var client = new MyService(); // generally works fine, except for things like Session
var result = client.Get(request); // throws NRE inside MyService
result.ShouldEqual("Test");
}
[Test]
public void Test_version_2()
{
var session = ObjectFactory.GetInstance<MockSession>();
session["key1"] = "Test";
var request = new MyRequest {Key = "key1"};
var client = ObjectFactory.GetInstance<MyService>();
var result = client.Get(request); // throws NRE inside MyService
result.ShouldEqual("Test");
}
[Test]
public void Test_version_3()
{
var session = ObjectFactory.GetInstance<MockSession>();
session["key1"] = "Test";
var request = new MyRequest {Key = "key1"};
var client = CreateNewRestClient();
var result = client.Get(request); // throws NotImplementedException here
result.ShouldEqual("Test");
}
}
It looks like you're trying to create unit tests, but you're using an AppHost like you wound an Integration test. See this previous answer for differences between the two and docs on Testing.
You can mock the Session by registering an instance in Request.Items[Keywords.Session], e.g:
[Test]
public void Can_mock_IntegrationTest_Session_with_Request()
{
using var appHost = new BasicAppHost(typeof(MyService).Assembly).Init();
var req = new MockHttpRequest();
req.Items[Keywords.Session] = new AuthUserSession {
UserName = "Mocked"
};
using var service = HostContext.ResolveService<MyService>(req);
Assert.That(service.GetSession().UserName, Is.EqualTo("Mocked"));
}
Otherwise if you set AppHost.TestMode=true ServiceStack will return the IAuthSession that's registered in your IOC, e.g:
[Test]
public void Can_mock_UnitTest_Session_with_IOC()
{
using var appHost = new BasicAppHost
{
TestMode = true,
ConfigureContainer = container =>
{
container.Register<IAuthSession>(c => new AuthUserSession {
UserName = "Mocked",
});
}
}.Init();
var service = new MyService {
Request = new MockHttpRequest()
};
Assert.That(service.GetSession().UserName, Is.EqualTo("Mocked"));
}

Resources