Orchard CMS connect external SQL Server - sql-server

I'm planning to create some pages which display data from an external SQL Server with Orchard CMS. It looks like I need to write a new module to implement this function. Is there any example or idea to implement this requirement?

Yes, you will need to write a new module, which provides a new content part and a content part driver. That driver will be responsible for fetching the data from the external SQL Server, which you will set to a property on the shape you will be returning from your driver. The shape's view will then display your data.
This tutorial will walk you through writing a custom content part: http://docs.orchardproject.net/en/latest/Documentation/Writing-a-content-part/
When you do, make sure not to create the content part Record type, since you will not be storing and loading data from the Orchard database - you want to load data from an external database. These are the steps you should follow:
Create a new module
Create a content part class
Have your part inherit from ContentPart, not ContentPart<TRecord> since there won't be any "TRecord".
Create a content part driver
On the Display method, return a shape by calling the ContentShape method. Make sure to add the SQL data access logic within the lambda. If you do it outside of that lambda, that data access code will be invoked every time the content item using your content part is invoked. Although that sounds as if that is exactly what you want, there's a subtlety here that involves Placement.info, which you can use to determine when your shape will actually be rendered or not. If the placement logic determines that your shape should not be rendered, then you don't want to access your external data for nothing.
Create a Placement.info file to configure the shape's placement (within the context of the content item being rendered).
Create the Razor view for the shape that you return in step 3.2.
Create a Migrations class that will define your custom content part, and any content types to which you want to add your part to. See http://docs.orchardproject.net/en/latest/Documentation/Understanding-data-access/ for more information on how to create migrations.
PS. Instead of implementing your data access code directly in the driver, I recommend you implement that in a separate class. Because you know, separation of concerns and such. You can then inject that service into your driver. To have your service class be registered with the service container, make sure that you define an interface for it, that itself derives from IDependency.
Some sample pseudo code:
Service code:
public interface IMyExternalDataStore : IDependency {
IList<MyExternalDataRecord> GetMyData();
}
public class MyExternalDataStore : IMyExternalDataStore {
public IList<MyExternalDataRecord> GetMyData() {
// Connect to your SQL Server database, perhaps using EF, load the data and return it. Could of course also be simply a DataSet.
}
}
Content Part:
public class MyExternalDataPart : ContentPart {
// Nothing here, unless you want to include some properties here that influence the data that you want to load. If so, you'll also want to implement the Editor methods in your content part driver, but I'm keeping it simple.
}
Content Part Driver:
public class MyExternalDataPartDriver : ContentPartDriver<MyExternalContentPart> {
private readonly IMyExternalDataStore _dataStore;
public MyExternalDataPartDriver(IMyExternalDataStore dataStore) {
_dataStore = dataStore;
}
protected override DriverResult Display(SlideShowProPart part, string displayType, dynamic shapeHelper) {
return ContentShape("Parts_MyExternalData", () => {
// Notice that we're performing the data access here within the lambda (the so called "shape factory method").
var data = _dataStore.GetMyData();
// Notice that I'm creating a property called "MyData"on the shape (which is a dynamic object).
return shapeHelper.Parts_MyExternalData(MyData: data));
}
}
}
Razor view for the Parts_MyExternalData shape:
Filename: Parts.MyExternalData.cshtml
#{
var records = (IList<MyExternalDataRecord>)Model.MyData;
}
<ul>
#foreach(var record in records) {
<li>#record.ToString()</li>
}
</ul>
Placement.info:
<Placement>
<Place Parts_MyExternalData="Content:0"/>
</Placement>
Migrations:
public class Migrations : DataMigrationImpl {
public int Create() {
// Define your content part so that you can attach it to any content type from the UI.
ContentDefinitionManager.AlterPartDefinition("MyExternalDataPart", part => part.Attachable());
// Optionally, define a new content type here programmatically or attach it to an existing type.
return 1;
}
}

Related

How to save and retrive view when it's needed

My goal is to keep session size as small as possible. (Why?.. it's other topic).
What I have is Phase listener declared in faces-config.xml
<lifecycle>
<phase-listener>mypackage.listener.PhaseListener</phase-listener>
</lifecycle>
I want to save all other views, except the last one(maximum two) , in some memcache. Getting the session map:
Map<String, Object> sessionMap = event.getFacesContext().getExternalContext().getSessionMap();
in beforePhase(PhaseEvent event) method is giving me access to all views. So here I could save all views to the memcache and delete them from the session. The question is where in jsf these views that are still loaded in the browser are requested so that I can refill with this view if it's needed. Is it possible at all? Thank you.
To address the core of your question, implement a ViewHandler, within which you can take control of the RESTORE_VIEW and RENDER_RESPONSE phases/processes. You'll save the view during the RENDER_RESPONSE and selectively restore, during the RESTORE_VIEW phase. Your view handler could look something like the following
public class CustomViewHandlerImpl extends ViewHandlerWrapper{
#Inject ViewStore viewStore; //hypothetical storage for the views. Could be anything, like a ConcurrentHashMap
ViewHandler wrapped;
public CustomViewHandlerImpl(ViewHandler toWrap){
this.wrapped = toWrap;
}
public UIViewRoot restoreView(FacesContext context, String viewId) throws IOException{
//this assumes you've previously saved the view, using the viewId
UIViewRoot theView = viewStore.get(viewId);
if(theView == null){
theView = getWrapped().restoreView(context, viewId);
}
return theView;
}
public void renderView(FacesContext context, UIViewRoot viewToRender) throws IOException, FacesException{
viewStore.put(viewToRender.getId(),viewToRender);
getWrapped().renderView(context, viewToRender);
}
}
Simply plug in your custom viewhandler, using
<view-handler>com.you.customs.CustomViewHandlerImpl</view-handler>
Of course, you probably don't want to give this treatment to all your views; you're free to add any conditions to the logic above, to implement conditional view-saving and restoration.
You should also consider other options. It appears that you're conflating issues here. If your true concern is limit the overhead associated with view processing, you should consider
Stateless Views, new with JSF-2.2. The stateless view option allows you to exclude specific pages from the JSF view-saving mechanism, simply by specifying transient="true" on the f:view. Much cleaner than mangling the UIViewRoot by hand. The caveat here is that a stateless view cannot be backed by scopes that depend on state-saving, i.e. #ViewScoped. In a stateless view, the #ViewScoped bean is going to be recreated for every postback. Ajax functionality also suffers in this scenario, because state saving is the backbone of ajax-operations.
Selectively set mark components as transient The transient property is available for all UIComponents, which means, on a per-view basis, you can mark specific components with transient="true", effectively giving you the same benefits as 1) but on a much smaller scope. Without the downside of no ViewScoped
EDIT: For some reason, UIViewRoot#getViewId() is not returning the name of the current view (this might be a bug). Alternatively, you can use
ExternalContext extCtxt = FacesContext.getCurrentInstance().getExternalContext();
String viewName = ((HttpServletRequest)extCtxt.getRequest()).getRequestURI(); //use this id as the key to store your views instead

Calling DAL from ViewModel asynchronously

I am building composite WPF application using MVVM-light. I have Views that have ViewModels injected into them using MEF:
DataContext = App.Container.GetExportedValue<ViewModelBase>(
ViewModelTypes.ContactsPickerViewModel);
In addition, I have ViewModels for each View (Screens and UserControls), where constructor usually looks like this:
private readonly ICouchDataModel _couchModel;
[ImportingConstructor]
public ContactsPickerControlViewModel(ICouchDataModel couchModel)
{
_couchModel = couchModel;
_couchModel.GetContactsListCompleted+=GetContactsListCompleted;
_couchModel.GetConcatcsListAsync("Andy");
}
Currently, I have some performance issues. Everything is just slow.
I have 2 kind of related questions
What is the right way of calling DAL methods asynchronously (that access my couchdb)? await/async? Tasks? Because currently I have to write a lot of wrappers(OnBegin, OnCompletion) around each operation, I have GetAsyncResult method that does some crazy things with ThreadPool.QueueUserWorkItem , Action etc.
I hope there is the more elegant way of calling
Currently, I have some screens in my application and on each screen, there are different custom UserControls, some of them need same data (or slightly changed) from DB.
Questions: what is the right way to share datasource among them? I am mostly viewing data, not editing.
Example: On Screen A: I have Contacts dropdown list user control (UC1), and contact details user control(UC2). In each user control, their ViewModel is calling DAL:
_couchModel.GetConcatcsListAsync("Andy");
And on completion I assign result data to a property:
List<ContactInfo> ContactsList = e.Resuls;
ContactsList is binded to ItemsSource of DropDownListBox in UC1. The same story happens in UC2. So I end up with 2 exactly same calls to DB.
Also If I go to Screen B, where I have UC1, I’ll make another call to DB, when I’ll go to Screen B from Screen A.
What is the right way to making these interaction ? e.g. Getting Data and Binding it to UC.
Thank you.
Ad.1
I think you can simply use Task.Factory to invoke code asynchronously (because of that you can get rid off OnBegin, OnCompletion) or if you need more flexibility, than you can make methods async.
Ad. 2
The nice way (in my opinion) to do it is to create DatabaseService (singleton), which would be injected in a constructor. Inside DatabaseService you can implement some logic to determine whether you want to refresh a collection(call DAL) or return the same (it would be some kind of cache).
Then you can call DatabaseService instead of DAL directly and DatabaseService will decide what to do with this call (get collection from DB or return the same or slightly modified current collection).
Edit:
DatabaseService will simply share a collection of objects between ViewModels.
Maybe the name "DBCacheService" would be more appropriate (you will probably use it only for special tasks as caching collections).
I don't know your architecture, but basically you can put that service in your client application, so the plan would be:
Create DatabaseService.cs
[Export(typeof(IDatabaseService))]
public class DatabaseService : IDatabaseService
{
private List<object> _contacts = new List<object>();
public async Task<List<object>> GetConcatcsList(string name)
{
if (_contacts.Count == 0)
{
//call DAL to get it
//_contacts = await Task.Factory.StartNew(() => dal.GetContactsList(name));
}
else
{
//refresh list if required (there could be some condition)
}
return _contacts;
}
}
Add IDatabaseService to your ViewModel's constructor.
Call IDatabaseService instead of DAL.
If you choose async version of DatabaseService, then you'll need to use await and change your methods to async. You can do it also synchronously and call it (whenever you want it to be asynchronous) like that:
Task.Factory.StartNew(() =>
{
var result = dbService.GetContactsList("Andy");
});
Edit2:
invoking awaitable method inside Task:
Task.Factory.StartNew(async () =>
{
ListOfContacts = await _CouchModel.GetConatcsList ("Andy");
});

MVVM Light, Windows Phone, View & ViewModel navigation between pages

I have a page where you basically select a set of options (configuration), and then you go to a next page, where you do some stuff
Using the MVVM Light toolkit, I have a viewmodel that binds to the view of the first page. when the user hits a button, it redirects to another view, which would be the 2nd page
i.e.:
Page2Command = new DelegateCommand((obj) =>
Messenger.Default.Send<Uri>(new Uri("/DoStuffView.xaml", UriKind.Relative),
Common.CommonResources.GoToDoStuffRequest)) });
The problem is, the viewmodel for the 2nd view (the way that I see it) has a couple of parameters in the constructor, which are basically the dependencies on the configuration that was set on the first page.
i.e. :
public DoStuffViewModel(ICollection<Note> availableNotes, SoundMappers soundType)
{
}
The problem lies here.. How can I instantiate the viewmodel with this data that was dynamically selected by the user on the 1st page?.
I can't use the ViewModelLocator pattern that MVVM light provides, since those viewmodels don't have any dependencies, they are just by themselves (or they can retrieve data from a db, file or whatever, but they don't have any dynamic input data). I could do it through the view's constructor, instantiate there the viewmodel, and assign to the view's DataSource the newly created viewmodel, but I think that's not very nice to do.
suggestions?
As I see you send messsage using Messenger class so you are familiar with messaging in MVVM light. You have to define your own message type that should accept your parameters from page 1:
public class Page2ViewModelCreateMessage : MessageBase
{
public ICollection<Note> AvailableNotes{get;set;}
public SoundMappers SoundType{get;set;}
public Page2ViewModelCreateMessage ()
{
}
public Page2ViewModelCreateMessage(ICollection<Note> availableNotes, SoundMappers soundType)
{
this.AvailableNotes = availableNotes;
this.SoundType = soundType;
}
}
You have to send an Page2ViewModelCreateMessage instance with you parameters and send it on navigating:
var message = new Page2ViewModelCreateMessage(myAvailableNotes, mySoundType)
Messenger.Default.Send(message);
On Page2 you have to register for recieving message of type Page2ViewModelCreateMessage:
Messenger.Default.Register<Page2ViewModelCreateMessage>(this, OnPage2ViewModelCreateMessage);
..
public void OnPage2ViewModelCreateMessage(Page2ViewModelCreateMessage message)
{
var page2ViewModel = new Page2ViewModel(messsage.AvailableNotes, message.SoundType);
}
As you can see I have replace your DoStuffViewModel with Page2ViewModel to be more clear.
I hope this will help you.
NOTE:I dont guarantee that code will work as its written in notepad.
The way I do this is to have a central controller class that the ViewModels all know about, via an interface. I then set state into this before having the phone perform the navigation for me. Each ViewModel then interrogates this central class for the state it needs.
There are a number of benefits to this for me:
It allows me to have non-static ViewModels.
I can use Ninject to inject the concrete implementation of the controller class and have it scoped as a singleton.
Most importantly, when tombstoning, I only need to grab the current ViewModel and the controller class.
I ran into a problem with messaging where my ViewModel was the registered listener, because I was View First and not ViewModel First, I was forced to use static ViewModel references. Otherwise the ViewModel wasn't created in time to receive the message.
I use the controller class in conjunction with messages (it is basically the recipient of all messages around the UI) so in future if I refactor, I don't need to change much, just the recipients of the messages.
Come to think of it, the controller class is also my navigation sink - as I have some custom navigation code that skips back paging on certain pages etc.
Here's an example of my current set up:
public interface IController
{
Foo SelectedFoo { get; }
}
public class ViewModel
{
private IController _controller;
public ViewModel(IController controller)
{
_controller = controller;
}
private void LoadData()
{
// Using selected foo, we load the bars.
var bars = LoadBars(_controller.SelectedFoo);
}
}
You could use PhoneApplicationService dictionary to save data you need when navigation from first event, and parse it when you navigateTo second page. you can also use that data in your ViewModels.
Something like this:
PhoneApplicationService.Current.State["DatatFromFirstPage"] = data;
and when navigating to second page:
if (PhoneApplicationService.Current.State.ContainsKey("DatatFromFirstPage"))
{
var dataUsedOnSeconPage= PhoneApplicationService.Current.State["DatatFromFirstPage"];
}
you can use this data globally in entire app

Creating Pivotviewer Collection

I'm trying to create a JIT pivotviewer and I have been kinda struggling a bit. Could someone clear my confusion on how the cxml is dynamically created? Also how should the information be set up for me to request it? I currently have it sitting inside of my database, do I need to create an xml doc for it to load from or can it pull it straight from the db?
For building a JIT PivotViewer collection you start by downloading the JIT example built by Microsoft.
Look around in the solution, when getting started the most important bit is the CollectionFactories project. To create a collection using data from your database you need to create your custom CollectionFactory.
Your custom collectionfactory extends the CollectionFactoryBase class:
class MyCustomCollection : CollectionFactoryBase
the class needs to implement the MakeCollection method, all this method has to do is create an instance of Collection class and add CollectionItems to it.
public override PivotServerTools.Collection MakeCollection(CollectionRequestContext context) {
return MakeCollection();
}
private static PivotServerTools.Collection MakeCollection() {
PivotServerTools.Collection collection = new PivotServerTools.Collection();
collection.Name = "MyImages";
ItemImage[] fileList = ImageListFromDatabase();
foreach (ItemImage image in fileList) {
collection.AddItem(image.Name, image.ImageUrl.ToString(), image.Description, image, null);
}
return collection;
}
Now to use this collection and see it in action, you need to provide the name of the collection for the PivotViewer Silverlight application (PivotServer) in the solution:
default.aspx
<param name="initParams" value="cxml=MyImages.cxml" />

LinqToSql how to implement calculated columns

I want to have a field in my entity where the returned data comes from a class function in mydomainservice and not from the database.
The reason is that I want to generate an image URL (Silverlight bind) based rather loosely upon other fields in a table
How can I obtain that ?
The other two have mentioned a partial class. They are correct. Here's an example...
public partial class MyImage
{
public string CompleteUrl
{
get { return string.Format("http://{0}/{1}/{2}.png", Host, Folder, Filename); }
}
}
This would assume that you already have columns named "Host", "Folder", and "Filename" in your database, and those have already been mapped to the appropriate columns.
L2S generates partial classes for all of its implementations. You shouldn't be doing your own mapping. These partial classes allow you to create a new file (with ClassName.cs) that will allow you to extend the functionality of your domain objects.
You can extend your linq2sql generated class by making a partial class with the same name (in the same namespace) and putting the method in that file.
Declare a partial class with the same name as the entity class and in the same assembly. Declare your function/property as usual.

Resources