I am having an issue using nHibernate and Rhino.Security. After struggling for hours to get the right config setup, I finally got the code to run without any errors. However, no entries are being saved to the database unless I call session.Flush().
Looking at various examples on the net; I should not have to call flush.
Here’s my config code:
var cfg = new Configuration()
.SetProperty(Environment.ConnectionDriver, typeof(SqlClientDriver).AssemblyQualifiedName)
.SetProperty(Environment.Dialect, typeof(MsSql2008Dialect).AssemblyQualifiedName)
.SetProperty(Environment.ConnectionString, "………")
.SetProperty(Environment.ProxyFactoryFactoryClass, typeof(ProxyFactoryFactory).AssemblyQualifiedName)
.SetProperty(Environment.ReleaseConnections, "on_close")
.SetProperty(Environment.UseSecondLevelCache, "true")
.SetProperty(Environment.UseQueryCache, "true")
.SetProperty(Environment.CacheProvider, typeof(HashtableCacheProvider).AssemblyQualifiedName)
.AddAssembly("GA.CAP.Website")
;
Security.Configure<AspNetUser>(cfg, SecurityTableStructure.Prefix);
var factory = cfg.BuildSessionFactory();
var session = factory.OpenSession();
var authorizationRepository = new AuthorizationRepository(session);
IoC.Container.RegisterInstance<IAuthorizationRepository>(authorizationRepository);
var permissionBuilderService = new PermissionsBuilderService(session, authorizationRepository);
IoC.Container.RegisterInstance<IPermissionsBuilderService>(permissionBuilderService);
var permissionService = new PermissionsService(authorizationRepository, session);
IoC.Container.RegisterInstance<IPermissionsService>(permissionService);
var authService = new AuthorizationService(permissionService, authorizationRepository);
IoC.Container.RegisterInstance<IAuthorizationService>(authService);
Test code:
authorizationRepository.CreateUsersGroup("GAAdmins");
var group = authorizationRepository.GetUsersGroupByName("GAAdmins");
The GetUsersGroupByName call returns null. If I add a session.Flush call in between the two calls, it works fine and returns the group.
Based on examples in various blogs, such as this one, I should not have to call flush. In addition, the test cases included with the Rhino.Security code do not do any flushing as shown here:
This is straight out of Rhino.Security's test case fixture:
// on first deploy
Operation operation = authorizationRepository.CreateOperation("/Account/View");
// when creating account
UsersGroup group = authorizationRepository.CreateUsersGroup("Belongs to " + account.Name);
// setting permission so only associated users can view
permissionsBuilderService
.Allow(operation)
.For(group)
.On(account)
.DefaultLevel()
.Save();
// when adding user to account
authorizationRepository.AssociateUserWith(user, group);
bool allowed = authorizationService.IsAllowed(user, account, "/Account/View");
Assert.True(allowed);
Is there some setting I am missing somewhere?
Thanks,
Rick
That is expected, RS uses the same session as your code, and calling Flush internally may result in unintended consequences.
Commit your transaction or call Flush
Related
Background; it was working with SP2013, but a supplier has switched to SP365.
Modifying the authentication using OfficeDevPnP.Core.AuthenticationManager, ClientID and ClientSecret I can get the access token. I can then do all the JSON reads I like, but it will only allow me to write two items to a list (orders), then it just times out. I restart the project and it does exactly the same. I can read the list to make sure the order hasn't been uploaded already, but when it comes to writing the third item it just throws timeout errors.
I updated the code to call for a new access token for each write and just get "Token Request Failed" after the second write.
Any thoughts on how to approach the supplier on config options, or change my approach?
Thanks in advance.
Found the answer, changing up the usage of GetAppOnlyAuthenticatedContext to something like this works wonders.
public void CreateListItemV2(string listName, QDS_WorkOrderEntry entry)
{
OfficeDevPnP.Core.AuthenticationManager authMgr = new OfficeDevPnP.Core.AuthenticationManager();
using (var context = authMgr.GetAppOnlyAuthenticatedContext(SPSiteUrl, "<clientid>", "<secret>"))
{
List list = context.Web.Lists.GetByTitle(listName);
var itemCreateInfo = new ListItemCreationInformation();
var newItem = list.AddItem(itemCreateInfo);
newItem["HHSDetails"] = entry.HHSDetails?.HHSDetailsId;
...
newItem.Update();
context.Load(newItem);
context.ExecuteQuery();
}
}
I have a small C# console application who's sole purpose is to receive records from a "Saved Search" in NetSuite(via SuiteTalk). I've been able to successfully connect and receive records from NetSuite for my Saved Search(the search runs fine through the web interface too), however when I attempt to access the results of the "Saved Search" through my application, I am unable to view them because the search object that is returned does not contain any data in the "recordList" property:
//Connect
var dataCenterAwareNetSuiteService = new DataCenterAwareNetSuiteService("XXXXXX");
dataCenterAwareNetSuiteService.Timeout = 1000 * 60 * 60 * 2;
//Adds Credentials etc...
dataCenterAwareNetSuiteService.tokenPassport = createTokenPassport();
//Setup Preferences
var prefs = new Preferences();
prefs.warningAsErrorSpecified = true;
prefs.warningAsError = false;
dataCenterAwareNetSuiteService.preferences = prefs;
var searchPrefs = new SearchPreferences();
dataCenterAwareNetSuiteService.searchPreferences = searchPrefs;
dataCenterAwareNetSuiteService.searchPreferences.pageSize = 5;
dataCenterAwareNetSuiteService.searchPreferences.pageSizeSpecified = true;
dataCenterAwareNetSuiteService.searchPreferences.bodyFieldsOnly = false;
dataCenterAwareNetSuiteService.searchPreferences.returnSearchColumns = false;
//Search
var tranSearchAdv = new TransactionSearchAdvanced();
var tranSearchRow = new TransactionSearchRow();
var tranSearchRowBasic = new TransactionSearchRowBasic();
tranSearchAdv.savedSearchId = "XXXX";
tranSearchRowBasic.internalId =
new SearchColumnSelectField[] { new SearchColumnSelectField() };
tranSearchRowBasic.tranId =
new SearchColumnStringField[] { new SearchColumnStringField() };
tranSearchRowBasic.dateCreated =
new SearchColumnDateField[] { new SearchColumnDateField() };
tranSearchRowBasic.total =
new SearchColumnDoubleField[] { new SearchColumnDoubleField() };
tranSearchRowBasic.entity =
new SearchColumnSelectField[] { new SearchColumnSelectField() };
tranSearchRow.basic = tranSearchRowBasic;
tranSearchAdv.columns = tranSearchRow;
//No errors,
//this works correctly and returns the "Saved Search" with the correct "totalRecords"
//but results.recordList == null while results.totalRecords = 10000000+
var results = dataCenterAwareNetSuiteService.search(tranSearchAdv);
I appears to me that the "recordList" object is the principal way data is retrieved from the results of a search(Related Java Example, Another Here). This is also the way the example API does it.
I have run this on multiple "Saved Search's" with the same results. I don't understand how you can have more than one record in "totalRecords" and yet the "recordList" remains null? Is there some configuration option that has to be set to allow me to access this property. Or maybe it's a security thing, the API user I have setup should have full access, is there anything else that need to be granted access?
NetSuite SuiteTalk is not well documented, and most of the examples online are not in C#, and not dealing with the issues that I'm experiencing. These factors make it very difficult to determine why the previously mentioned behavior is occurring, or even, to discover any alternative methods for retrieving the resulting data from the source "Saved Search".
Does anyone have any insight into this behavior? Is this the correct method of retrieving results from SuiteTalk? Is there any configuration from the API or Web Side that needs to be changed?
Update 1
I've also tried using the alternative way of getting result data by accessing the "searchRowList" object from the "SearchResult" object(suggested by #AdolfoGarza) However it returns mostly empty fields(null) similar to the "recordList" property I do not see a way to retrieve "Saved Search" data from this method.
Try getting the results with results.searchRowList.searchRow , thats how it works in php.
I was able to resolve the issue by removing this line in the code:
tranSearchRow.basic = tranSearchRowBasic;
Then like #AdolfoGarza reccomended, retrieving the results from "basic" field in "results.searchRowList"
For some reason the template API that I was using was setting up a "TransactionSearchAdvanced" referencing a blank "TransactionSearchBasic" record, not sure why but this was causing the results from "searchRowList" to be null. After removing it I now get non-null values in the proper fields.
As for "recordList", it's still null, not sure why, but as I have my data I don't think I'll continue to dig into this.
I'm using C# to work with AD (Win 2012R2).
We are syncing AD users,groups and their relationship to SQL database.
Full sync works well.
But when using synchronization cookie, the relationship changes does not detected.
What may be the reason?
Thanks.
Here is my code:
public void DirSyncChanges(DirectoryEntry de, byte[] cookie)
{
DirectorySynchronization syncData = new DirectorySynchronization(cookie);
srch = new DirectorySearcher(de)
{
Filter = "(&(objectClass=user)(objectCategory=person))",
SizeLimit = Int32.MaxValue,
Tombstone = true
};
srch.DirectorySynchronization = syncData;
syncData.Option = DirectorySynchronizationOptions.None;
using(SearchResultCollection results = srch.FindAll())
foreach (SearchResult res in results)
{
//results is empty. no loop
}
}
Please specify the DirectorySearcher.PropertiesToLoad. Only if any of the attributes in PropertiesToLoad are updated, you will get them in delta sync.
As i remember the search root of DirSync must be naming context root object.
Better use paged search. No matter how large the value you set to SizeLimit. It will only return at most 1000 or 1500 (forgot exact number) results.
My answer is based on .NET 3.5.
I am posting this because it might help someone using the VersionOne API SDK Client. I wanted to change the status of a test programmatically, to one of the following categories: Ready, InTesting, Passed, or Failed. I originally tried to change the attribute 'Status.Name' however I would get an error that the attribute is a Read-Only attribute. Another suggestion was to create a new attribute with the same name and that the new attribute would override the previous read-only attribute with the same name. However, it appears that I was looking at it backwards.
internal void TestStatusPassed(string str_TestID)
{
var testId = Oid.FromToken(str_TestID, _context.MetaModel);
var query = new Query(testId);
var testType = _context.MetaModel.GetAssetType("Test");
var sourceAttribute = testType.GetAttributeDefinition("Status.Name");
query.Selection.Add(sourceAttribute);
var result = _context.Services.Retrieve(query);
var test = result.Assets[0];
var oldSource = GetValue(test.GetAttribute(sourceAttribute).Value);
test.SetAttributeValue(sourceAttribute, "Passed");
_context.Services.Save(test);
}
This code will throw an exception "Cannot change a read-only attribute"...
I pulled the XML data for one test from the VersionOne Rest API and noticed a relation named "TestStatus" and then it had a number '9123' assigned to it. So I moved that test manually to 'In Testing' and the "TestStatus" changed to '9121'. Then I moved it to failed and the "TestStatus" changed to '155'. I repeated this with several tests from different testsets and noticed that the numbers for each status were consistent and then changed the code slightly and then I was able to programmatically change the status of each test. I changed "Status.Name" to "Status" and "Passed" to "TestStatus:9123" and now it moves the test into the passed category programmatically.
internal void TestStatusPassed(string str_TestID)
{
var testId = Oid.FromToken(str_TestID, _context.MetaModel);
var query = new Query(testId);
var testType = _context.MetaModel.GetAssetType("Test");
var sourceAttribute = testType.GetAttributeDefinition("Status");
query.Selection.Add(sourceAttribute);
var result = _context.Services.Retrieve(query);
var test = result.Assets[0];
var oldSource = GetValue(test.GetAttribute(sourceAttribute).Value);
test.SetAttributeValue(sourceAttribute, "TestStatus:9123");
_context.Services.Save(test);
}
Using System.DirectoryServices, one can get the highestCommittedUSN this way:
using(DirectoryEntry entry = new DirectoryEntry("LDAP://servername:636/RootDSE"))
{
var usn = entry.Properties["highestCommittedUSN"].Value;
}
However, I need to get this information from a remote ADLDS using System.DirectoryServices.Protocols, which does not leverage ADSI. Following is a simplified code sample of what I'm attempting to do:
using(LdapConnection connection = GetWin32LdapConnection())
{
var filter = "(&(highestCommittedUSN=*))";
var searchRequest = new SearchRequest("RootDSE", filter, SearchScope.Subtree, "highestCommittedUSN");
var response = connection.SendRequest(searchRequest) as SearchResponse;
var usn = response.Entries[0].Attributes["highestCommittedUSN"][0];
}
Unfortunately this kicks back a "DirectoryOperationException: The distinguished name contains invalid syntax." At first I thought there might be something wrong in GetWin32LdapConnection() but that code is called in numerous other places to connect to the directory and never errors out.
Any ideas?
Thanks for the idea, Zilog. Apparently to connect to the RootDSE, you have to specify null for the root container. I also switched the filter to objectClass=* and the search scope to "base." Now it works!
using(LdapConnection connection = GetWin32LdapConnection())
{
var filter = "(&(objectClass=*))";
var searchRequest = new SearchRequest(null, filter, SearchScope.Base, "highestCommittedUSN");
var response = connection.SendRequest(searchRequest) as SearchResponse;
var usn = response.Entries[0].Attributes["highestcommittedusn"][0];
}
I hope this saves someone else some time in the future.