I am currently developing a custom task and I'm stuck on a problem.
My Custom Task consists of three files:
MBTask that contains the class that implements the interface "Task"
MBTaskUI that implements the interface "IDtsTaskUI"
MBForm which is a Form.
In MBTaskUI on the Initialize() function i reveive the TaskHost object and save it in a variable. And then in the GetView() function o send this TaskHost to my Form builder
public void Initialize(TaskHost taskHost, IServiceProvider serviceProvider)
{
this.taskHost = taskHost;
IDtsConnectionService cs = serviceProvider.GetService
(typeof(IDtsConnectionService)) as IDtsConnectionService;
this.connections = cs.GetConnections();
}
public ContainerControl GetView()
{
return new MBForm(this.taskHost, this.connections);
}
It work great and i can use this TaskHost in my Form to get parameters when i load the Form and save them when I close it.
String script_tmp = (String)th.Properties["myScript"].GetValue(th);
SqlConnection conn_tmp = (SqlConnection)th.Properties["myConnection"].GetValue(th);
th.Properties["myScript"].SetValue(th, myScript);
th.Properties["myConnection"].SetValue(th, myConnectionTarget);
And so, when i re-open my Task Editor, i use the parameters i received to initialize some objects.
But, and here is my problem, in my MBTask class, i have a Validate() function which verify the parameters (myConnection and myScript). and these parameters are always null (also after I normally initialized it by using the MBForm and the close function.
So, what I don't understand is why my parameters were not instanced ?
Isn't it the job of "th.Properties["myScript"].SetValue(th, myScript);" ?
myScript and myConnection are declared public in my MBTask.
public class MBTask : Task
{
public SqlConnection myConnection { get; set; }
public String myScript { get; set; }
I know these parameters are saved because i can get them back when i re-open the editor. So why are they null when I do the Validate() ?
Do I have to add a link to the TaskHost from the MBTaskUI and the one from the MBTask ?
It seems that there is something i don't understand here ...
Thanks for your help,
Léo Lejeune.
I fond the solution:
The system I implemented was correct. But if you want to use complex parameters (SQLConnection) you have to use XML saving.
So, to use the default saving parameter of the task, only use simple objects like String and Integer.
And the Validate function can't use parameters because they are not yet instanced and so they are null.
Related
I've recently moved from MVC5 over to .NET Core 2.1 (MVC). Can anyone help me with this please.
I have my ApplicationUser and I've extended the model/table to store the user's FirstName.
In the View, I want to be able to output the current user firstname value.
User in the view is a ClaimsPrincipal so I need to go off to the DB to grab the value I need or access UserManager to get it.
Now, I know I can get that in the controller but I don't want to have to create a JQuery call to grab it every time I need it.
What I do want is to be able to access it server side, ideally via a static helper class.
In the MVC5 I'd have a helper to do the job no problem. Something like this for example:
public static string GetCurrentUserFirstName()
{
string _usrRef = HttpContext.Current.User.Identity.GetUserId();
var user = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(_usrRef);
return user.FirstName;
}
However, .NET Core doesn't work that way.
In a controller I could say:
var user = await _userManager.GetUserAsync(User);
string firstName = user.FirstName;
or I could go off to the DB via a call using Dapper w/ my connection string.
I can't inject the UserManager or ConnectionStrings into the helper via the constructor as it is static.
Is there a way to access either of those in this static helper?
It's the little changes that get you the most!
Thanks to #Kirk Larkin - I've found the solution.
I have to admit, it feels a little more convoluted having to pass things around to gain access to them but this is a good, working solution.
The View:
#using Microsoft.AspNetCore.Identity
#using MyApplication.Helpers
#inject UserManager<ApplicationUser> UserManager
<div>
#await MyHelper.GetLoggedInUserFirstName(UserManager, User)
</div>
The MyHelper file:
public static async Task<string> GetLoggedInUserFirstName(UserManager<ApplicationUser> userManager, ClaimsPrincipal user)
{
string output = "";
try
{
var currentUser = await userManager.GetUserAsync(user);
if(currentUser!=null)
{
output = currentUser.FirstName ?? currentUser.Email;
}
}
catch(Exception e) { }
return output;
}
I have the following dependency chain:
IUserAppService
IUserDomainService
IUserRepository
IUserDataContext - UserDataContextImpl(string conn)
All interfaces above and implementations are registered in a Windsor Castle container. When I use one connection string, everything works fine.
Now we want to support multiple databases, In UserAppServiceImpl.cs, we want to get different IUserRepository (different IUserDatabaseContext) according to userId as below:
// UserAppServiceImpl.cs
public UserInfo GetUserInfo(long userId)
{
var connStr = userId % 2 == 0 ? "conn1" : "conn2";
//var repo = container.Resolve<IUserRepository>(....)
}
How can I pass the argument connStr to UserDataContextImpl?
Since the connection string is runtime data in your case, it should not be injected directly into the constructor of your components, as explained here. Since however the connection string is contextual data, it would be awkward to pass it along all public methods in your object graph.
Instead, you should hide it behind an abstraction that allows you to retrieve the proper value for the current request. For instance:
public interface ISqlConnectionFactory
{
SqlConnection Open();
}
An implementation of the ISqlConnectionFactory itself could depend on a dependency that allows retrieving the current user id:
public interface IUserContext
{
int UserId { get; }
}
Such connection factory might therefore look like this:
public class SqlConnectionFactory : ISqlConnectionFactory
{
private readonly IUserContext userContext;
private readonly string con1;
private readonly string con2;
public SqlConnectionFactory(IUserContext userContext,
string con1, string con2) {
...
}
public SqlConnection Open() {
var connStr = userContext.UserId % 2 == 0 ? "conn1" : "conn2";
var con = new SqlConnection(connStr);
con.Open();
return con;
}
}
This leaves us with an IUserContext implementation. Such implementation will depend on the type of application we are building. For ASP.NET it might look like this:
public class AspNetUserContext : IUserContext
{
public string UserId => int.Parse(HttpContext.Current.Session["UserId"]);
}
You have to start from the beginning of your dependency resolver and resolve all of your derived dependencies to a "named" resolution.
Github code link:https://github.com/castleproject/Windsor/blob/master/docs/inline-dependencies.md
Example:
I have my IDataContext for MSSQL and another for MySQL.
This example is in Unity, but I am sure Windsor can do this.
container.RegisterType(Of IDataContextAsync, dbEntities)("db", New InjectionConstructor())
container.RegisterType(Of IUnitOfWorkAsync, UnitOfWork)("UnitOfWork", New InjectionConstructor(New ResolvedParameter(Of IDataContextAsync)("db")))
'Exceptions example
container.RegisterType(Of IRepositoryAsync(Of Exception), Repository(Of Exception))("iExceptionRepository",
New InjectionConstructor(New ResolvedParameter(Of IDataContextAsync)("db"),
New ResolvedParameter(Of IUnitOfWorkAsync)("UnitOfWork")))
sql container
container.RegisterType(Of IDataContextAsync, DataMart)(New HierarchicalLifetimeManager)
container.RegisterType(Of IUnitOfWorkAsync, UnitOfWork)(New HierarchicalLifetimeManager)
'brands
container.RegisterType(Of IRepositoryAsync(Of Brand), Repository(Of Brand))
controller code:
No changes required at the controller level.
results:
I can now have my MSSQL context do its work and MySQL do its work without any developer having to understand my container configuration. The developer simply consumes the correct service and everything is implemented.
I have a singleton class that looks something roughly like this (only with more bindable public properties):
public class Session extends EventDispatcher
{
private var _Id:String;
private static const _instance:Session = new Session( SingletonLock );
private static const SESSID_CHANGED:String = 'SessionIdChanged';
public function Session( lock:Class ){
//SingletonLock is an empty class not available outside this file
if( lock != SingletonLock ){
throw new Error("Don't instantiate Session. Use Session.instance");
}
_Id = "";
}
public static function get instance():Session{
return _instance;
}
// Changes a blob object (from the server xml for sessions) to a session object
public function updateFromXMLObj(s:ObjectProxy):void
{
_instance.Id = s.Id;
}
[Bindable(event=SESSID_CHANGED)]
public function get Id():String{
return _Id;
}
public function set Id(new_id:String):void{
if(this._Id != new_id){
this._Id = new_id;
this.dispatchEvent(new Event(SESSID_CHANGED));
}
}
public function registerOnSessionChange(listener:Function):void{
addEventListener(SESSID_CHANGED,listener);
}
public function unregisterOnSessionChange(listener:Function):void{
removeEventListener(SESSID_CHANGED,listener);
}
}
The idea is that in some mxml code, I have a databinding expression like the following:
<mx:HTTPService id="homeReq" url="{URLs.homepath(Session.instance.Id)}" ... />
where I want the url for homeReq to be updated when the sessionId changes. In addition, other parts of the code (written in Actionscript) need to be able to register their listeners for when the sessionId changes, so they call registerOnSessionChange and unregisterOnSessionChange to manage those listeners.
The abnormal behavior I'm discovering is that the event listeners registered through registerOnSessionChange are indeed being called when the session Id changes, but the MXML data binding expression is not updating. I've tried all combinations of dispatching the event during the capture phase, and making it not cancelable, but to no avail. My understanding of [Bindable (event= ...)] is that the MXML should update the url string when the event specified is dispatched, so what am I doing wrong or misunderstanding?
Note: I realize there are lots of different ways of doing the singleton pattern in Actionscript, but unless the way I am doing it is actually causing my problem somehow, I'd appreciate not getting sidetracked by discussing alternatives.
I think that {URLs.homepath(Session.instance.Id)} this is not binding to a variable instead is executing a method of an object, have you tried to do something like this:
[Bindable]
private var _url:*
Then setting the initial value to _url at init or complete:
_url = {URLs.homepath(Session.instance.Id)};
Linking to the binded variable in the MXML
<mx:HTTPService id="homeReq" url="{_url}" ... />
Then updating the _url variable should automatically update the HTTPService url...
Make an MXML form containing a combobox for course number of 5th semester. On selecting the coruse, display the course name and max marks for the selected course.
Data Binding: <mx:Binding>
I want to create a property on my LINQ To SQL designer-generated class that gets and sets a formatted type, like that:
public partial ALinqClass
{
public string formatedValue
{
get { return formatValue(TheValue); }
set { TheValue = RemoveFormating(value); }
}
}
TheValue is the property generated by the Linq designer.
How do I decorate public string formatedValue so I can bind it to controls on my form?
For example: When I use Visual Studio to create a Object Data Source from my linq object/class all properties linq generated are present on the Object data Source, but formatedValue is not.
Why ?
WHY ?
WHHHHHHHHY ????????!!!!!
Thank you.
Fábio
Linq-to-SQL generated entities are declared as partial classes so you should be able to create another file and add custom properties to the same partial class. This is so if you have to regenerate the classes, your additions to the entities are still available in a different file.
Also as long as these properties are public, you should be able to databind them just like generated properties.
For Windows Forms Databinding, you need either
A datasource, which is derived from Control.
An intermediate component, BindingSource, acting as link between the LinqToSql datasource and bound controls.
I'll outline how to use BindingSource.
private BindingSource binding1;
private YourDataContext context;
void Form1_Load(object sender, EventArgs e) {
// initialize the data context
context = new YourDataContext();
// initialize the BindingSource
binding1 = new BindingSource();
binding1.DataSource = context.YourObjects;
// bind controls to BindingSource
listBox1.DataSource = binding1;
listBox1.DisplayMember = "Name";
}
Obviously, this short sample is not complete, but should give you an idea on how to start. Further information can be found at Data Binding and Windows Forms.
Mark
I think this is the answer I wanted. Linq must have a few more classes and inheritances, but I think this will do.
http://msdn.microsoft.com/en-us/library/system.componentmodel.bindableattribute.aspx
[Bindable(true)]
public int MyProperty
{
get {
// Insert code here.
return 0;
}
set {
// Insert code here.
}
}
I am trying to figure out how to notify the user which field failed to validate.
I setup LINQ to SQL class datacontext to access a database from ASP.net pages. Since user input will be from by web interface forms and import from Excel files, i would like the write the validation logic in one place. The idea behind this is when i import from excel. I will collect the error messages for each row, and display a summary, somehow. A logical place seems to extend the class generated by LINQ to SQL. According to most documentation and examples, i should do something like this:
public partial class Customer
{
partial void OnTitleChanging(string value)
{
if (!Char.IsUpper(value[0])) {
throw new ValidationException(
"Title must start with an uppercase letter.");}
}
}
The problem with this approach is that validation will stop on the first failed field.
In Windows Forms Link1, if I define an ErrorProvider component in the form and set the DataSource property of it to your BindingSource the exception will be indicated by a red circle right to the validated control. The tooltip of this red circle will show the exception message.
Is there something similar for ASP.net pages? I am using the listview control and inline editing in the listview.
Updates:
- I actually did something similar to what Nick Carver is suggesting. Link2 . Instead of throwing an exception, i record an error message.
public partial class PQSSClassesDataContext
{
public partial class ErrorFeilds
{
private static List<string> Messages = new List<string>();
public void AddErrorMessage(string message)
{
Messages.Add(message);
}
public List<string> GetErrorMessages()
{
return Messages;
}
}
}
I am actually stuck on how to map the error message to the field. That's why i was looking for something like ErrorProvider. I am already using events instead of exceptions to record errors. Any idea how to mark the corresponding failed field from the codebehind file?
Any help appreciated.
What we have done in the past is simply have an error collection on the DataContext, extend it just adding something like a List<ValidationError>. Then all you need to do is override SubmitChanges() and check if you have any validation errors, and decide to abort, throw them, handle however you wish really at that point...all before calling base.SubmitChanges()
We're in a ASP.Net per-request life-cycle, but if your Context is around longer make sure to clear the error list.
It's handy for your ValidationError class/objects to contain a reference to a common base or interface that all your classes implement so you can point to the object later from the error if needed. (e.g. get the ID for throwing the error labels or other info in the right place).
Example classes:
public class ValidationError {
public string Message { get; set; }
public IBase { get; set; }
}
public interface IBase {
public long ID { get; set; }
public DateTime DateModified { get; set; }
}
There is the ValidationSummary control, that works with the individual validation controls to show a list of errors. But the action of the WinForms ErrorProvider is performed in ASP.NET by the individual validation controls, which derive from the Label control