I'm in the process of making live a .net system. I am using LINQ and MVC. I had to create the live database and hoped that this would run smoothly however it did not.
New SQL SERVER - Microsoft Windows NT 5.0 (2195) / 8.00.760
I created an administrator user who can add/edit/delete. Basically I receive the following error if I try to add (.InsertOnSubmit) or delete (.DeleteOnSubmit) any rows however not when I edit.
"Network access for Distributed Transaction Manager (MSDTC) has been disabled. Please enable DTC for network access in the security configuration for MSDTC using the Component Services Administrative tool."
I've Googled this error and found people believe its to do with "MSDTC service" however this seems to be ticked on the service. I have logged into the database by SQL Server Management and this user can add/delete.
One Example:
Controller
if (_service.AddAccess(access)) return RedirectToAction("Access");
public Repository()
{
_db = new DataClassDataContext(ConfigurationManager.ConnectionStrings["RegistrarsServices"].ConnectionString);
}
public void Save()
{
_db.SubmitChanges();
}
public bool AddAccess(Access access)
{
try
{
using (var scope = new TransactionScope())
{
_db.Accesses.InsertOnSubmit(access);
Save();
scope.Complete();
}
return true;
}
catch (Exception)
{
return false;
}
}
*Please note this did work when using the development server. Microsoft Windows NT 5.2 (3790) / 10.0.1600.22
Controller
private readonly ServiceAdministration _service = new ServiceAdministration();
public ActionResult AddAccess()
{
return View(new EmailViewModel());
}
[HttpPost]
public ActionResult AddAccess(EmailViewModel emailViewModel)
{
if (emailViewModel.Button == "Back") return RedirectToAction("Access");
if (!ModelState.IsValid) return View(emailViewModel);
Access access = new Access();
access.emailAddress = emailViewModel.emailAddress;
if (_service.AddAccess(access)) return RedirectToAction("Access");
emailViewModel.errorMessage = "An error has occurred whilst trying to grant access. Please try again later.";
return View(emailViewModel);
}
Service
readonly Repository _repository = new Repository();
public bool AddAccess(Access access)
{
return _repository.AddAccess(access);
}
Don't really know what I am missing.
Thanks in advance for any help.
Clare :-)
Do you have any idea why are you triggering distributed transactions? This is what you need to investigate. Usual culprit is multiple ADO.Net connection from a single TransactionScope. See ADO.NET and System.Transactions and ADO.NET and LINQ to SQL. Make sure you use a single connection (ie. LINQ2SQL context) in a transaction scope. You shouldn't have to use more than one per HTTP call anyway.
Related
My Controller code
ParaEntities db = new ParaEntities();
public List<Client> GetAllClients()
{
return db.Client.ToList();
}
Please click this link to see the error message
It is weird that when I am first time to click the button to get all client information then it responses 500. In the second time, I click the button to get all client, which is success.
You should assign variable and display the data in View.
Please change the syntax as i write below.
ParaEntities db = new ParaEntities();
public List<Client> GetAllClients()
{
var getData= db.Client.ToList();
if(getData==null)
{
return null;
}
return getData;
}
This error points to a connection problem rather then code issue. Check that the connectionstring is valid and that the user specified in the connectionstring has access to the database. If you're running the application on IIS then make sure that the applicationpool user has access to the database. Here is another SO issue were they solved this error.
If you want to store the db context as a local variable in your controller class then I suggest you to instantiate it inside of the controllers constructor. Then you make sure that every time a instance of the controller is created then a new db context is created as well.
Lets say your controller namned ClientController
private ParaEntities db;
public ClientController()
{
this.db = new ParaEntities();
}
public List<Client> GetAllClients()
{
return db.Client.ToList();
}
Another approach is to wrap your db context in a using statment inside of your method. In that case you make sure that the method is using a fresh context when being called upon and that the context is being disposed when the operation is completed.
public List<Client> GetAllClients()
{
using(ParaEntities db = new ParaEntities())
{
return db.Client.ToList();
}
}
PS: both examples violates the dependency inversion principle (hard coupling to the db context) but thats for another day
Please try this
public List<Client> GetAllClients()
{
ParaEntities db = new ParaEntities();
return db.Client.ToList();
}
We have an ASP.Net 4 / MVC 3 hybrid web application which uses NInject 3 and (Fluent) NHibernate 3.2. DB is SQL Server 2008 R2. Server is 6-core 28 GB Windows 2008 64-bit server.
Our customer has recently started testing the site using a spidering tool. As soon as the site experiences the load produced by the spider, our log starts to fill up with exceptions.
We see a variety of errors from NHibernate, including some of the following:
NHibernate.TransactionException: Commit failed with SQL exception ---> System.Data.SqlClient.SqlException: The transaction operation cannot be performed because there are pending requests working on this transaction.
System.Data.SqlClient.SqlException (0x80131904): The server failed to resume the transaction. Desc:410000050f. The transaction active in this session has been committed or aborted by another session.
System.NullReferenceException: Object reference not set to an instance of an object. at System.Data.SqlClient.SqlInternalTransaction.GetServerTransactionLevel()....
NHibernate.Exceptions.GenericADOException: could not execute native bulk manipulation query:exec [Stats.InsertListingStatsList] #ListingStats =:ListingStats[SQL: exec [Stats.InsertListingStatsList] #ListingStats =#p0] ---> System.Data.SqlClient.SqlException: New request is not allowed to start because it should come with valid transaction descriptor.
to give just four examples. All have a similar flavour - they all seem to relate to the management of transactions by ADO.Net as the substrate of NHibernate.
Now, some details of our NH implementation:
SessionFactory is static;
SessionFactory uses AdoNetTransactionFactory;
ISession is in request scope, and stored in the HttpContext.Items collection;
Repositories are also in request scope;
We are now using config.CurrentSessionContext();
Each call to our generic repository uses a transaction
Here are two methods from our repository.
public T GetById<T>(int id)
{
using (var t = Session.BeginTransaction())
{
var entity = Session.Get<T>(id);
t.Commit();
return entity;
}
}
public void Add<T>(T entity)
{
using (var t = Session.BeginTransaction())
{
Session.Save(entity);
t.Commit();
}
}
My question is simple: what is going wrong? What is causing these apparent conflicts between transactions, or between the various data-related operations that our domain instigates as it de/hydrates our domain?
UPDATE: here is our full configuration:
public FluentConfiguration BuildConfiguration(string connectionString)
{
var sqlConfig = MsSqlConfiguration.MsSql2008.ConnectionString(connectionString).AdoNetBatchSize(30);
var config = Fluently.Configure().Database(sqlConfig);
var entityMapping = AutoMap.AssemblyOf<User>(new AutomappingConfiguration())
.UseOverridesFromAssemblyOf<UserMappingOverride>()
.AddMappingsFromAssemblyOf<TableNamingConvention>()
.Conventions.AddFromAssemblyOf<TableNamingConvention>();
var cqrsMapping = AutoMap.AssemblyOf<AdvertView>(new QueryAutomappingConfiguration())
.UseOverridesFromAssemblyOf<AdvertViewMappingOverride>();
config.Mappings(c => c.AutoMappings.Add(entityMapping));
config.Mappings(c => c.AutoMappings.Add(cqrsMapping));
config.Mappings(c => c.HbmMappings.AddFromAssemblyOf<AdvertView>());
config.ExposeConfiguration(c => c.SetProperty(Environment.TransactionStrategy, typeof(AdoNetTransactionFactory).FullName));
config.CurrentSessionContext<WebSessionContext>();
return config;
}
More code for you guys and gals. Here is the relevant section of our IoC Container configuration.
var domainEntityBootstrapper = new DomainEntitySessionBootStrapper("Domain", "NHibernate.ISession.Domain", _enableLucine, HttpContextItemsProvider);
Bind<ISessionFactory>().ToMethod(domainEntityBootstrapper.CreateSessionFactory).InSingletonScope().Named(domainEntityBootstrapper.Name);
Bind<ISession>().ToMethod(domainEntityBootstrapper.GetSession).InRequestScope();
var queryBootstrapper = new QueryEntitySessionBootStrapper("Query", "NHibernate.ISession.Query", HttpContextItemsProvider);
Bind<ISessionFactory>().ToMethod(queryBootstrapper.CreateSessionFactory).InSingletonScope().Named(queryBootstrapper.Name);
Bind<ISession>().ToMethod(queryBootstrapper.GetSession).WhenInjectedInto(typeof (QueryExecutor)).InRequestScope();
and here is the code from the GetSession() method of the base class for these SessionBootstrappers (please note that the CreateSessionFactory method calls the BuildConfiguration method above and then calls BuildSessionFactory()).
public virtual ISession GetSession(IContext context)
{
var items = GetHttpContextItems();
var session = default(ISession);
var sessionExists = items.Contains(SessionKey);
if (!sessionExists)
{
session = context.Kernel.Get<ISessionFactory>(Name).OpenSession();
items.Add(SessionKey, session);
}
else
{
session = (ISession)items[SessionKey];
}
return session;
}
// a Func which serves access to the HttpContext.Current.Items collection
private Func<IDictionary> GetHttpContextItems { get; set; }
Please note that we use two sessions, one for ordinary domain de/hydration and one for CQRS, hence the pair of bindings in the Container.
The error messages indicate that you are not managing transactions correctly. I think the root cause is that you are handling transactions in the repository methods which in my opinion is a very poor design. Your repositories should have an ISession injected into their constructors, and your controllers should have any repositories they are dependent upon injected into their constructors. It's easy to wire this all up with Ninject. With this approach you can use transaction-per-request or (much better imo) manage the transaction in the action methods.
Here's how I'm setting up NHibernate with Ninject in NinjectWebCommon. The root cause of your problem may be that you are binding the ISession in request scope and storing it in HttpContext, which is unnecessary. I am also confused why you have two sets of bindings for Domain and Query.
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ISessionFactory>().ToProvider(new SessionFactoryProvider()).InSingletonScope();
kernel.Bind<ISession>().ToProvider(new SessionProvider()).InRequestScope();
}
private class SessionFactoryProvider : Provider<ISessionFactory>
{
protected override ISessionFactory CreateInstance(IContext context)
{
// create and configure the session factory
// I have a utility class to do this so the code isn't shown
return nhibernateHelper.BuildSessionFactory();
}
}
private class SessionProvider : Provider<ISession>
{
protected override ISession CreateInstance(IContext context)
{
var sessionFactory = context.Kernel.Get<ISessionFactory>();
var session = sessionFactory.OpenSession();
session.FlushMode = FlushMode.Commit;
return session;
}
}
A sample controller action using a transaction. Managing transactions outside of the repositories is important for several reasons:
Allows multiple repositories to participate in a transaction
Allows the controller to set the transaction boundaries (unit of work)
Allows lazy loads to occur in the transaction
Transactions are needed for read operations if second level caching is used. Even if it caching isn't used I think it's a best practice
public ActionResult EditDocuments(int id, string name)
{
using (var txn = _session.BeginTransaction())
{
var summary = _characterizationRepository
.GetCharacterization(id)
.AsCharacterizationSummaryView()
.ToFutureValue();
var documents = _characterizationRepository
.GetCharacterization(id)
.SelectMany(c => c.Documents)
.OrderBy(d => d.FileName)
.AsDocumentSelectView(true)
.ToFuture();
if (summary.Value == null)
{
throw new NotFoundException(_characterizationRepository.ManualId, "Characterization", id);
}
CheckSlug(name, summary.Value.Title);
var model = new DocumentSectionEditView()
{
CharacterizationSummary = summary.Value,
Documents = documents.ToArray()
};
txn.Commit();
return View(model);
}
}
It seems you are using the wrong context manager, check if you are using the WebSessionContext. This context manager will bind your session to the httpcontext of the current call instead of the thread. What happens now under load (the spider), when you are using the ThreadStaticSessionContext, session will 'jump' to an other 'call'.
I added a new asp.net project which only hosts (Classic) WebServices on top of my MVC app.
The Web Service calls the Biz Objects which are located in Biz Layer Dlls.
WebService clients are just like the regular users, they have to be authenticated and authorized per operations.
I am using a SOAP authentication token to validate the user upon first call, then passing that token around per following calls.
BizObjects access the IUserSessionManager to get the authorized user, and then call the authorize the user per request. This was pretty easy with the MVC app and the Windows app that the BusinessObjects are called from.
So how do I store user info in the following system where my BusinessObjects can retrieve them from. (This might be easy for you but I am not comfortable working with Web Services)
public class XyzUserSessionManager
{
private static IXyzUserSessionManager _instance;
public static IXyzUserSessionManager UserSessionManager
{
get { return _instance; }
set { _instance = value; }
}
public static IXyzUserSession Current
{
get { return UserSessionManager.Current; }
}
}
public IXyzUserSession Current
{
get
{
if (HttpContext.Current == null || HttpContext.Current.Session == null || HttpContext.Current.Session[SessionKey] == null)
return null;
return (IXyzUserSession)HttpContext.Current.Session[SessionKey];
}
protected set
{
HttpContext.Current.Session[SessionKey] = value;
}
}
You can enable session state support just like for regular web apps. This is done on a per-method base. See more details here: http://msdn.microsoft.com/en-us/library/aa480509.aspx
I have seen some of the questions/answers related to this topic here, however still I am not getting the suggestion which I want. So I am posting my question again here, and I would be thankful for your valuable time and answers.
I would like to create “Component, Page, SG, Publication, Folders “ via programmatically in SDL Tridion Content Manager, and later on, I would like to add programmatically created components in Page and attach CT,PT for that page, and finally would like to publish the page programmatically.
I have done these all the activities in SDL Tridion 2009 using TOM API (Interop DLL's), and I tried these activities in SDL Tridion 2011 using TOM.Net API. It was not working and later on I came to know that, TOM.Net API will not support these kinds of works and it is specifically only for Templates and Event System. And finally I came to know I have to go for Core services to do these kinds of stuffs.
My Questions:
When I create console application to create component programmatically using core service, what are the DLL’s I have to add as reference?
Earlier, I have created the exe and ran in the TCM server, the exe created all the stuffs, can I used the same approach using core services too? Will it work?
Is BC still available or Core Service replaced BC? (BC-Business Connector)
Can anyone send some code snippet to create Component/Page (complete class file will be helpful to understand better)
You will only need to reference Tridion.ContentManager.CoreService.Client.dll. You may want to reference Tridion.Common.dll to get access to some helpful classes such as TcmUri, but it is not needed.
You client program will make an explicit connection with the core service on a machine that you specify. If done properly, you can run the client both on the same machine as the Tridion Content Manager or on a different machine.
The Business Connector is still available, but has been superseded by the Core Service.
Have a look at these links:
Updating Components using the Core Service in SDL Tridion 2011
In SDL Tridion 2011, how can I process metadata on an item using the Core Service?
And the standard documentation on the topic connecting to the Core Service from .NET.
If you need more help with the code, I suggest you show us the code you've already written and explain what isn't working.
I will try to answer your questions:
You have to reference Tridion.ContentManager.CoreService.Client and add some stuff to app.config. It's described here
It will work from CM server, as well as from any other machine, provided it can access CoreService
CoreService is replacement for BC. BC is deprecated and will be dropped soon
You will get all the basic info from here.
This should be enough for you to start. If you will have specific problems - post them as a seperate questions.
From How can i use engine object in my console application
From a console application you should use the Core Service. I wrote a small example using the Core Service to search for items in the content manager.
Console.WriteLine("FullTextQuery:");
var fullTextQuery = Console.ReadLine();
if (String.IsNullOrWhiteSpace(fullTextQuery) || fullTextQuery.Equals(":q", StringComparison.OrdinalIgnoreCase))
{
break;
}
Console.WriteLine("SearchIn IdRef:");
var searchInIdRef = Console.ReadLine();
var queryData = new SearchQueryData
{
FullTextQuery = fullTextQuery,
SearchIn = new LinkToIdentifiableObjectData
{
IdRef = searchInIdRef
}
};
var results = coreServiceClient.GetSearchResults(queryData);
results.ToList().ForEach(result => Console.WriteLine("{0} ({1})", result.Title, result.Id));
Add a reference to Tridion.ContentManager.CoreService.Client to your Visual Studio Project.
Code of the Core Service Client Provider:
public interface ICoreServiceProvider
{
CoreServiceClient GetCoreServiceClient();
}
public class CoreServiceDefaultProvider : ICoreServiceProvider
{
private CoreServiceClient _client;
public CoreServiceClient GetCoreServiceClient()
{
return _client ?? (_client = new CoreServiceClient());
}
}
And the client itself:
public class CoreServiceClient : IDisposable
{
public SessionAwareCoreServiceClient ProxyClient;
private const string DefaultEndpointName = "netTcp_2011";
public CoreServiceClient(string endPointName)
{
if(string.IsNullOrWhiteSpace(endPointName))
{
throw new ArgumentNullException("endPointName", "EndPointName is not specified.");
}
ProxyClient = new SessionAwareCoreServiceClient(endPointName);
}
public CoreServiceClient() : this(DefaultEndpointName) { }
public string GetApiVersionNumber()
{
return ProxyClient.GetApiVersion();
}
public IdentifiableObjectData[] GetSearchResults(SearchQueryData filter)
{
return ProxyClient.GetSearchResults(filter);
}
public IdentifiableObjectData Read(string id)
{
return ProxyClient.Read(id, new ReadOptions());
}
public ApplicationData ReadApplicationData(string subjectId, string applicationId)
{
return ProxyClient.ReadApplicationData(subjectId, applicationId);
}
public void Dispose()
{
if (ProxyClient.State == CommunicationState.Faulted)
{
ProxyClient.Abort();
}
else
{
ProxyClient.Close();
}
}
}
When you want to perform CRUD actions through the core service you can implement the following methods in the client:
public IdentifiableObjectData CreateItem(IdentifiableObjectData data)
{
data = ProxyClient.Create(data, new ReadOptions());
return data;
}
public IdentifiableObjectData UpdateItem(IdentifiableObjectData data)
{
data = ProxyClient.Update(data, new ReadOptions());
return data;
}
public IdentifiableObjectData ReadItem(string id)
{
return ProxyClient.Read(id, new ReadOptions());
}
To construct a data object of e.g. a Component you can implement a Component Builder class that implements a create method that does this for you:
public ComponentData Create(string folderUri, string title, string content)
{
var data = new ComponentData()
{
Id = "tcm:0-0-0",
Title = title,
Content = content,
LocationInfo = new LocationInfo()
};
data.LocationInfo.OrganizationalItem = new LinkToOrganizationalItemData
{
IdRef = folderUri
};
using (CoreServiceClient client = provider.GetCoreServiceClient())
{
data = (ComponentData)client.CreateItem(data);
}
return data;
}
Hope this gets you started.
HI,
I am implementing a custom role provider in my nhibernate application
I have a repository that I call whenever I want to access the nhibernate session.
So when my role provider initializes itself
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config) {
base.Initialize(name, config);
Repository = new Repository();
}
Then I override
public override string[] GetRolesForUser(string username) {
var users = Repository.QueryAll<Users>();
//I then filter and so on
}
But when this function is called I always get an error that the NHibernate session is closed.
I debugged the nhibernate source code and it turns out that the session here has a different guid that the session in my controllers(I am using ASP.NET MVC also).
And this particular session is closed by the time I get here.
I don't know who closes it. I know it is started when the application starts and only then.
Does anyone have any idea what I am doing wrong?
I want to still use Nhibernate in this provider but not get the error any more.
Thank you
I had what appears to be the exact same problem. Don't forget that Role and Membership providers are only instantiated once and exist for the lifetime of the application. If you're using a Session per Web request pattern, the ISession will be closed after the first request and then any reference to an ISession internal to the provider will likely be null for subsequent requests.
You can get around this by injecting a reference to the ISessionFactory and calling GetCurrentSession, instead of directly holding a reference to an ISession.
This is how I evetually fixed it.
in my repository class I had this:
public Repository()
{
this.Session = SessionManager.GetCurrentSession();
}
I deleted the constructor entirely
I put in this instead:
private ISession _session;
protected ISession Session
{
get
{
if (_session == null)
{
_session = SessionManager.GetCurrentSession();
}
return _session;
}
}