I have some very basic code:
NHibernate.ISession session = doSomeStuffWithNHibernateSession();
Using the object inspector in the Visual Studio debugger, I am able to open the ActionQueue of the session object and list all the pending NHibernate commands.
Is there a way to access it programmatically ? Being able to access properties like InsertionCount or HasAnyQueuedAction would be enough.
This should work (using explicit type names instead of var to simplify their finding in NH)
NHibernate.ISession session = ...
// here we get the access to underling implementation
NHibernate.Impl.SessionImpl sessionImpl = session
.GetSessionImplementation() as NHibernate.Impl.SessionImpl;
// and we can now work with action queue
var actionQueue = sessionImpl.ActionQueue;
// and check it
var count = actionQueue.InsertionsCount;
var hasAnyQueuedActions = actionQueue.HasAnyQueuedActions;
Related
The issue I am having is that the newly added AD groups don't seem to be immediately searchable via GroupPrincipal.FindByIdentity() method.
Below is the code I used for adding the group.
// to add a new AD group
using (var group = new GroupPrincipal(context, groupName))
{
group.GroupScope = GroupScope.Universal;
group.Save();
}
One thing I'd like to mention here is that the PrincipalContext object context is only created once at the constructor of my AD service class, and I am reusing the same context object throughout the life of the service class. Not sure if this would cause any potential issues here.
So what can I do to get the most up-to-date AD groups right after the new groups are added?
I could achive this by adding a CommitChanges on the underlying directory entry.
public static void Test()
{
var context = PrincipalContextProvider.ProvideContext();
for (int i = 0; i < 10; i++)
{
using (var group = new GroupPrincipal(context, $"Hello_World_{i}"))
{
group.GroupScope = GroupScope.Universal;
group.Save();
((DirectoryEntry)group.GetUnderlyingObject()).CommitChanges();
}
var _group = GetGroup($"CN=Hello_World_{i},CN=Users,DC=abc,DC=com");
Console.WriteLine(_group.Name);
}
}
For explanation: The PrincipalContextProvider simply provides a context as you use in your code. The CommitChanges method, saves changes that are made to a directory entry to the underlying directory store. You also need the Save method! And at least, the GetGroups methods queries the group by its LDAP Path (its uses a new principal context and i'm not sure if it makes any differents). Hope it helps to go forward.
In Epicor 9 it was fairly easy to open Visual Studio and create a project and use the Epicor libraries to access its Business Objects (BOs). So, for instance the Part could be accessed by including the library Epicor.Mfg.Part and newing up a Part object. Then it was easy to get information for a part by calling Part.GetByID("partnum");. This would return a PartDataSet.
It is different but not so difficult to do the same thing in Epicor 10. However, I have noticed that the PartDataSet does not contain any UD fields, even UD fields that have been properly set up in Epicor10.
How can the UD fields be accessed when tapping into Epicor 10 through its business objects?
EDIT:
using Erp.BO;
using Erp.Proxy.BO;
// ...
var binding = Epicor.ServiceModel.StandardBindings.NetTcp.UsernameWindowsChannel();
var cc = new ClientCredentials();
var cred = cc.UserName;
cred.UserName = "****";
cred.Password = "****";
DnsEndpointIdentity ep = new DnsEndpointIdentity("****");
var quoteBo = new QuoteImpl(binding, new Uri("net.tcp://****/Erp/BO/Quote.svc"), cc, ep);
var qds = new QuoteDataSet();
var hed = qds.QuoteHed.NewQuoteHedRow(); // type: QuoteDataSet.QuoteHedRow
// I am not getting UserDefinedColumns as a member of hed.
// This gives me a compiler error.
qds.QuoteHed[0].UserDefinedColumns["Custom_c"] = "value";
It is still fairly easy, the DS returned by the call to the BO will be defined in the contract DLL found on both the client and the server, as this file needs to be distributed to the client machines the UD fields are not added to it. It would cause too many client updates.
This means the Visual Studio cannot look at the contract assembly to determine the field names. Instead, you access the field using the columnName indexer i.e:
class Program
{
static void Main(string[] args)
{
// Hard-coded LogOn method
// Reference: Ice.Core.Session.dll
Ice.Core.Session session = new Ice.Core.Session("manager", "manager", "net.tcp://AppServer/MyCustomerAppserver-99999-10.0.700.2");
// References: Epicor.ServiceModel.dll, Erp.Contracts.BO.ABCCode.dll
var abcCodeBO = Ice.Lib.Framework.WCFServiceSupport.CreateImpl<Erp.Proxy.BO.ABCCodeImpl>(session, Erp.Proxy.BO.ABCCodeImpl.UriPath);
// Call the BO methods
var ds = abcCodeBO.GetByID("A");
var row = ds.ABCCode[0];
System.Console.WriteLine("CountFreq is {0}", row.CountFreq);
System.Console.WriteLine("CustomField_c is {0}", row["CustomField_c"]);
System.Console.ReadKey();
}
}
UserDefinedColumns is defined in Epicor.ServiceModel but is inaccessible as it is an internal property of Ice.IceRow which Erp.Tablesets.QuoteHedRow inherits from.
When you've found the specific record your looking for and have an object containing all of the columns for the record you should see an additional object named UserDefinedColumns. It works like a dictonary that is of type <string, object>. So for instance to set a value out you would do something like this:
myPartDs.Part[0].UserDefinedColumns["MyUdColumn_c"] = "some value";
If you need to pull a value out then you will have to parse it to whatever type it needs to be because they are stored as objects.
Using NotificationHubClient I can get all registered devices using GetAllRegistrationsAsync(). But if I do not use the registration model but the installation model instead, how can I get all installations? There are methods to retrieve a specific installation but none to get everything.
You're correct, as of July 2016 there's no way to get all installations for a hub. In the future, the product team is planning to add this feature to the installations model, but it will work in a different way. Instead of making it a runtime operation, you'll provide your storage connection string and you'll get a blob with everything associated with the hub.
Sorry for visiting an old thread... but in theory you could use the GetAllRegistrationsAsyc to get all the installations. I guess this will return everything without an installation id as well, but you could just ignore those if you choose.
Could look something like this
var allRegistrations = await _hub.GetAllRegistrationsAsync(0);
var continuationToken = allRegistrations.ContinuationToken;
var registrationDescriptionsList = new List<RegistrationDescription>(allRegistrations);
while (!string.IsNullOrWhiteSpace(continuationToken))
{
var otherRegistrations = await _hub.GetAllRegistrationsAsync(continuationToken, 0);
registrationDescriptionsList.AddRange(otherRegistrations);
continuationToken = otherRegistrations.ContinuationToken;
}
// Put into DeviceInstallation object
var deviceInstallationList = new List<DeviceInstallation>();
foreach (var registration in registrationDescriptionsList)
{
var deviceInstallation = new DeviceInstallation();
var tags = registration.Tags;
foreach(var tag in tags)
{
if (tag.Contains("InstallationId:"))
{
deviceInstallation.InstallationId = new Guid(tag.Substring(tag.IndexOf(":")+1));
}
}
deviceInstallation.PushHandle = registration.PnsHandle;
deviceInstallation.Tags = new List<string>(registration.Tags);
deviceInstallationList.Add(deviceInstallation);
}
I am not suggesting this to be the cleanest chunk of code written, but it does the trick for us. We only use this for debugging type purposes anyways
What's the precise differences between the following three lines in a MVC controller inheriting from ServiceStackController?
(I cannot find the difference explained in any documentation)
//A - (default: reload = true)
var session = GetSession();
//B
var session = GetSession(false);
//C
var session = SessionAs<IAuthSession>();
GetSession is better named GetOrCreateSession as it will either Get a Typed Session or create a new one if it doesn't exist. It also stores the instance of the Session in HTTP Request Context where if reload:false will return the local instance when it exists:
IAuthSession session = GetSession(reload:false);
IAuthSession session = GetSession(reload:true);
If reload:true it will always retrieve the Session from the underlying ICacheClient.
SessionAs<T> always gets the Session from the ICacheClient and returns an empty instance if it doesn't exist. It also returns a typed version of your Custom AuthUserSession:
CustomUserSession session = SessionAs<CustomUserSession>();
In new version of TeamFoundation 2013 default build templates, the Workspace variable is missing. It is needed as intput parameter for few key activities like ConvertWorkspaceItem. How do I get current workspace for TfvcTemplate.12.xaml templates? I've tried to use this msdn thread but it's not working for me (returns null workspace name). Any suggestions?
There's a new activity in 2013 called GetLocalPath that replaces ConvertWorkspaceItem.
The activity is under the Microsoft.TeamFoundation.Build.Activities.Core namespace in the Microsoft.TeamFoundation.Build.Activities assembly.
It uses the LocalPathProvider class that aggregates all workspaces used in the build and exposes path translation for all of them in one place. This basically removes the dependency of knowing the workspace in order to translate server paths to local paths and allows you to use as many workspaces as you want without worrying about breaking something down the line.
When MS takes something away, it's usually for a good reason. "hacking" is really not necessary.
I went with a hack using internal classes from Microsoft.TeamFoundation.Build.Activities.dll (used by microsoft to create workspace name). You need to create custom activity with following code:
public sealed class GetDefaultWorkspace : BaseActivity<Workspace>
{
public override Activity CreateBody()
{
var type = typeof(TfGetSources).Assembly.GetType("Microsoft.TeamFoundation.Build.Activities.TeamFoundation.TfGetSources+GetDefaultWorkspaceName");
var activity = (CodeActivity<string>)Activator.CreateInstance(type);
var sequence = new Sequence();
var workspaceName = new Variable<string>();
sequence.Variables.Add(workspaceName);
sequence.Activities.Add(activity);
activity.Result = (OutArgument<string>) workspaceName;
sequence.Activities.Add(new GetWorkspace
{
Name = workspaceName,
Result = new LambdaReference<Workspace>(ctx => Result.Get(ctx))
});
return sequence;
}
}
This answer might work better for some people. ghord's answer works well, and passes the Workspace back where it can be used in the XAML. However, for my purposes I only want the workspace in my custom TFS activities, so I ended up with this alternative...
public sealed class CustomActivity : CodeActivity
{
protected override void Execute(CodeActivityContext context)
{
// get workspace
var buildDetail = context.GetExtension<IBuildDetail>();
var buildAgent = context.GetExtension<IBuildAgent>();
var buildDirectory = buildAgent.GetExpandedBuildDirectory(buildDetail.BuildDefinition);
var workspacePath = Path.Combine(buildDirectory, "src");
var wsInfo = Workstation.Current.GetLocalWorkspaceInfo(workspacePath);
var tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(wsInfo.ServerUri);
tfs.Connect(ConnectOptions.None);
var vcs = tfs.GetService<VersionControlServer>();
// finally can get to the workspace here
var workspace = vcs.GetWorkspace(workspacePath);
}
}
Using this method, I don't have to have an activity that just returns the workspace, and then have to pass the workspace into other TFS activities. I just get the workspace from within my own activity while it runs.
I believe the method employed here will use the already downloaded workspace. Keep in mind, that this approach will only work within the scope of "Run on agent" sequence after "Initialize Environment" and before ResetEnvironment within the finally statement of Try Compile, Test, Publish. Else, the workflow will have no knowledge of a sources directory.
http://social.msdn.microsoft.com/Forums/vstudio/en-US/420ba073-bdf5-4ab4-88da-c84561d1a1ba/creating-dynamic-working-folder-in-tfs2013-defaulttemplate?forum=tfsbuild