compositecontrol - user control - different approaches - user-controls

I have seen this code to create a Login control, I guess instead of writing this code, we can use an .ascx file to create this control. Can someone explains the difference of these two approaches. thanks. source:http://www.joe-stevens.com/2010/04/16/creating-a-composite-server-control-with-asp-net/
[ToolboxData("<{0}:Login runat=server></{0}:Login>")]
public class Login : CompositeControl
{
private TextBox txtUsername = new TextBox();
private TextBox txtPassword = new TextBox();
private Button btnLogin = new Button();
protected override void CreateChildControls()
{
txtUsername.ID = "txtUsername";
txtPassword.ID = "txtPassword";
txtPassword.TextMode = TextBoxMode.Password;
btnLogin.ID = "btnLogin";
btnLogin.Text = "Login";
Controls.Add(txtUsername);
Controls.Add(txtPassword);
Controls.Add(btnLogin);
base.CreateChildControls();
}
}

Custom Server Controls typically serve a general purpose (beyond your application) and are typically built as a library to be shared across multiple applications. These are typically implemented and sold by third party vendors like Telerik, Infragistics, etc. User Controls are very centric to your application. You cannot share them across multiple applications (there may be some hacks, but generally not intended for that purpose). These are not built as libraries but as user interface components included in your application. Custom Server Controls don't provide designer support for building them but User Controls have designer support. So your example can be implemented both as a user control and custom server control depending upon what your intentions are for that control. That being said writing custom server controls is non-trivial. Here was a official description from MS
http://msdn.microsoft.com/en-us/library/aa719735.aspx

Related

Why my custom C# extention does not execute when deployed to Spotfire WebPlauer/Consumer

I have a simple custom Add-in that just displays a message to the user.
namespace GeorgiSpotfireCustomExtention
{
public class GeorgiEvent : CustomApplicationEventHandler
{
protected override void OnApplicationInstanceCreated(AnalysisApplication application)
{
base.OnApplicationInstanceCreated(application);
MessageBox.Show("On Application Instance Created");
}
}
}
That is my CustomAddIn class:
public sealed class CustomAddIn : AddIn
{
// Override methods in this class to register your extensions.
protected override void RegisterApplicationEventHandlers(ApplicationEventHandlerRegistrar registrar)
{
base.RegisterApplicationEventHandlers(registrar);
registrar.Register(new GeorgiEvent());
}
}
I am just trying to learn the package deployment process. When I am running it locally - in the installed Spotfire Analyst client it displays the message just fine:
However, when I package the extention, add it to the server (via the "Deployments & Packages" section, adding the "spk" file and then saving the area, the message is not shown when I try to open a document in the WebPlayer/Consumer.
Notes: I am choosing "TIBCO Spotfire Any Client" for my intended client in the Package Builder when building the spk file.
from the Spotfire Wiki (emphasis mine):
WinForms graphical user interface is a component of the .NET Framework and not something supplied by Tibco Spotfire. It's not recommended to implement solutions using Forms, but sometimes it could be handy when debugging. There is no commitment that it will work in future versions of the Analyst client. Forms are not supported on the Web Player.
the example listed on the wiki is for IronPython, but presumably the same holds true for C# extensions.
Correct. My assumption, and I don’t really know a lot about .NET, so this is not absolute, is that the form is rendered on the machine executing the code. In the case of your example above, the dialog would pop on the Node Manager host. If you’re really set on using an alert like this, you can accomplish it in JavaScript with an ‘alert()’. There is probably a way to render dialogues o in the web client too, but I don’t know it offhand.

I wrote a Liferay module. How to make it configurable by administrators?

I have created a Liferay 7 module, and it works well.
Problem: In the Java source code I hard-coded something that administrators need to modify.
Question: What is the Liferay way to externalize settings? I don't mind if the server has to be restarted, but of course the ability to modify settings on a live running server (via Gogo Shell?) could be cool provided that these settings then survive server restarts.
More specifically, I have a module for which I would like to be able to configure an API key that looks like "3g9828hf928rf98" and another module for which I would like to configure a list of allowed structures that looks like "BASIC-WEB-CONTENT","EVENTS","INVENTORY".
Liferay is utilizing the standard OSGi configuration. It's quite a task documenting it here, but it's well laid out in the documentation.
In short:
#Meta.OCD(id = "com.foo.bar.MyAppConfiguration")
public interface MyAppConfiguration {
#Meta.AD(
deflt = "blue",
required = false
)
public String favoriteColor();
#Meta.AD(
deflt = "red|green|blue",
required = false
)
public String[] validLanguages();
#Meta.AD(required = false)
public int itemsPerPage();
}
OCD stands for ObjectClassDefinition. It ties this configuration class/object to the configurable object through the id/pid.
AD is for AttributeDefinition and provides some hints for the configuration interface, which is auto-generated with the help of this meta type.
And when you don't like the appearance of the autogenerated UI, you "only" have to add localization keys for the labels that you see on screen (standard Liferay translation).
You'll find a lot more details on OSGi configuration for example on enroute, though the examples I found are always a bit more complex than just going after the configuration.

mvvmcross login viewmodel-viewcontroller communciation

I am using Mvvmcross crosscore in my project
I am trying to bind my loginviewmodel to the loginviewcontroller
I bound a command for the login button. the app waits until it gets a login response, which is stored in the loginViewModel itself..
How can I communicate this to the loginviewcontroller --- regarding the login status and login error message if any
Can I access the viewmodel datacontext inside my loginviewcontroller ??? and how ?
What is the best approach to communication any items in the viewmodel back ( I basically mean all the NON-UI binding items)
I am using Mvvmcross crosscore in my project
I'm assuming from this that you followed the CrossLight sample N=39.
Can I access the viewmodel datacontext inside my loginviewcontroller ??? and how ?
If you followed N=39. then you can access the DataContext using the property called DataContext - see https://github.com/MvvmCross/NPlus1DaysOfMvvmCross/blob/master/N-39-CrossLight-Touch/CrossLightTouch/MyViewController.cs#L33
public object DataContext
{
get { return BindingContext.DataContext; }
set { BindingContext.DataContext = value; }
}
Beyond this, there are many other examples in the N+1 videos which demonstrate how to communicate between ViewModels and Views including error messages and loading dialogs - e.g. N=34 shows one implementation of progress dialogs - https://github.com/MvvmCross/NPlus1DaysOfMvvmCross/tree/master/N-34-Progress
A complete index of N+1 videos is available on http://mvvmcross.wordpress.com
Obviously not all of these are appropriate for your CrossLight approach to development, but this is where you can allow your custom mvvm approach to fill the gap - it's code for you to write in your custom framework.
One of the best methods solving viewmodel interdependencies is using a loosely coupled approch using the MessageBus/Event Aggregator pattern. There's a plugin for MvvmCross. Or you could use the excellent TinyMessenger.
In principle when using this approach, you no longer establish hard references between the publisher and consumers of arbitrary notifications. Instead notifications get published on a message bus and every one is free to listen and subscribe.

Domain driven design external systems and technical dependencies

I am designing a system using domain driven design concepts and I am struggling with a few things. The "domain" is essentially a business system for the company I work for. I am also using dependency injection. So, in my model I have things related to any typical business system (Employee, Order, Invoice, Deposit, etc..). Right now I am trying to create a cash posting application in which users (aka Employees) can create deposits and apply them to unpaid invoices. The problem that I am having is that we are also using an external business system (Microsoft Dynamics Nav) to handle our accounting transactions. So essentially I am dealing with two different databases. So, for the cash posting application I have modeled the domain objects Deposit and DepositLine. I also have in my domain an IDepositRepository interface that is responsible for persisting the deposits. To get a deposit from the system I just want to grab it directly from the database. However, in order to create a deposit I have to use the Dynamics Nav web services because there is certain logic that gets executed behind the scenes that I don't know about. I started looking at the concept of an Anti Corruption layer in which I could translate my version of the deposit object into a deposit object suitable for the web service. So here is what I am envisioning right now:
Domain Layer
- Models
- Deposit
- DepositLine
- Repositories
- IDepositRepository
Infrastructure Layer
- Data
- Repositories
- DepositRepository
- DynamicsNav
- Services
- INavCashManagementService
- Translators
- IDepositTranslator
- Adapters
- INavAdapter
Now I thought i might implement the DepositRepository like so:
public class DepositRepository
{
private INavCashManagementService navCashManagementService;
public DepositRepository(INavCashManagementService navCashManagementService)
{
this.navCashManagementService = navCashManagementService;
}
public Deposit GetDeposit(int id)
{
// use nhibernate to get directly from the database
}
public void SaveDeposit(Deposit deposit)
{
this.navCashManagementService.CreateDeposit(deposit);
}
}
First of all, is this an appropriate design? My next problem is that users are also going to have to "Post" deposits. The Nav web services will also have to be used to run the posting routine. But, this is more of a business process rather than a persistence issue, so I don't see it fitting into the repository. So I am wondering how/where I should call the posting routine. Should I create a domain service like this:
public class CashPostingDomainService
{
private INavCashManagementService navCashManagementService;
public CashPostingDomainService(INavCashManagementService navCashManagementService)
{
this.navCashManagementService = navCashManagementService;
}
public void PostDeposits()
{
this.navCashManagementService.PostDeposits();
}
}
One confusion I have with domain driven design is external dependencies. Doesn't the CashPostingDomainService class now have an external dependency on Nav? I know the implementation isn't in the domain layer, but doesn't the interface itself make it a dependency? The same goes with other technical concerns like sending emails. If I have an IEmailService interface and want to send an email once the deposits are posted, would I inject the interface into the CashPostingDomainService class? Or would that be part of the application workflow? So which one of these options make the most sense (if any):
1
public class DepositController
{
private ICashPostingDomainService cashPostingDomainService;
private IEmailService emailService;
public DepositController(
ICashPostingDomainService cashPostingDomainService,
IEmailService emailService)
{
this.cashPostingDomainService = cashPostingDomainService;
this.emailService = emailService;
}
public void PostDeposits()
{
this.cashPostingDomainService.PostDeposits();
this.emailService.NotifyDepositsPosted();
}
}
2
public class DepositController
{
private ICashPostingDomainService cashPostingDomainService;
public DepositController(
ICashPostingDomainService cashPostingDomainService)
{
this.cashPostingDomainService = cashPostingDomainService;
}
public void PostDeposits()
{
this.cashPostingDomainService.PostDeposits();
}
}
public class CashPostingDomainService
{
private INavCashManagementService navCashManagementService;
private IEmailService emailService;
public CashPostingDomainService(
INavCashManagementService navCashManagementService,
IEmailService emailService)
{
this.navCashManagementService = navCashManagementService;
this.emailService = emailService;
}
public void PostDeposits()
{
this.navCashManagementService.PostDeposits();
this.emailService.NotifyDepositsPosted();
}
}
Thanks for the help!
is this an appropriate design?
It seems fine to me. The important thing is for your Repository to stay oblivious of the Nav side of things and let the anticorruption layer handle that. You might want to have a look here for a similar example.
I know the implementation isn't in the domain layer, but doesn't the
interface itself make it a dependency?
You may have that feeling because the name of your (supposedly agnostic) service interface contains "Nav". To reflect a service abstraction that could have Nav or any other ERP as an implementation, you should rename it to ICashManagementService.
If I have an IEmailService interface and want to send an email once
the deposits are posted, would I inject the interface into the
CashPostingDomainService class? Or would that be part of the
application workflow?
It's your architectural decision to choose one or the other.
Option 1. means that sending an email is an intrinsic part of the deposit posting domain operation. If you take your domain module and reuse it in another application, posting deposits will automatically result in sending an email whatever that application is about. This might be the right thing to do in your context, or you might want to make things a little more generic (like, sending feedback after the operation but not deciding in the domain service whether this feedback should be mail, a log file, etc.)
Option 2. means that the sequence of events that happen after posting the deposits is application specific, that is at the use case level rather than business/domain level. It is up to the Controller (or Application Service) to decide which actions to take -send an email or anything else. Consequently, different applications based around your domain layer could decide to take different actions. This also means possible code duplication between these applications if several of them chose to send mails.

Deploy two connected webparts in a page layout during feature activation?

I've implemented 2 webparts (deriving from Microsoft.SharePoint.WebPartPages.WebPart, the WSS 3 WebPart), one of which is a provider and the other the consumer (implementing ASP.net connection model, with ConnectionProviderAttribute and ConnectionConsumerAttribute methods).
I managed to deploy them in a feature which also deploys a Page Layout containing two webpart zones, which are themselves populated during the FeatureAvtivated method of the feature receiver, with the 2 newly created webparts. All of this works just fine.
For information, I used this link to make it work. Beware, the method using AllUsersWebPart tag in elements.xml, shown in links like this one (http://www.andrewconnell.com/blog/archive/2007/10/07/Having-Default-Web-Parts-in-new-Pages-Based-Off-Page.aspx) work, but if you deactivate, then reactivate your feature, you just have double webparts in your future pages based on the layout. The method described here (http://sharepoint.coultress.com/2008/06/adding-web-part-to-page-layout.html) just threw me an error when analysing metadata for the layout aspx file (the problem seemed to come from the line in the ZoneTemplate tag).
My next goal is to connect these webparts together right after all this, thus enabling the end user to create pages, based on the layout, containing by default the two webparts connected together (right now everything works except for the connected part).
I tried something like this, using ASP.net connection model (the other one, WSS model, throws logically an error because I'm not implementing the good interfaces). But even though the connection resulting from the "mgr.SPConnectWebParts()" method doesn't throw any exception and actually adds the connection to the connection list of the webpart manager, I can see in debug mode that the connection property 'IsActive" is false (maybe normal), and that when I create a new page based on the layout, the webparts appear not connected.
Any guess? I believe there's something with the fact that the webparts cannot be connected before the page containing them is actually created, but I'm far from sure of it.
Declarative web part connection provisioning is actually quite straightforward:
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Module Name="Module1">
<File Path="Module1\default.aspx" Url="demo.aspx">
<AllUsersWebPart ID="testProvider">...</AllUsersWebPart>
<AllUsersWebPart ID="testConsumer">...</AllUsersWebPart>
<WebPartConnection ID="testConnection"
ProviderID="testProvider"
ProviderConnectionPointID="providerID"
ConsumerID="testConsumer"
ConsumerConnectionPointID="consumerID" />
</File>
</Module>
</Elements>
Details:
http://blogs.code-counsel.net/Wouter/Lists/Posts/Post.aspx?ID=161
You can find connection point IDs with PowerShell if you first connect your web parts manually:
$web = Get-SPWeb <WebURL>
$wpman = $web.GetLimitedWebPartManager("<PageURL>", [System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared)
$wpman.SPWebPartConnections
Tried creating the web parts on the page programmatically? You'll have far fewer headaches than trying to do it declaratively.
Look up the SPLimitedWebPartManager class for how to handle web parts on a provisioned page.
Also, web parts in a web part zone are tied to the URL of the page on which they are added. This is by design of the the ASP.NET Web Part Manager.
Thus, if you added web parts to zones on a page layout at directory: http://webapp/sites/site/_catalog/master/mypagelayout.aspx - the web parts will ONLY appear on that page. Createa new page at /sites/site/Pages/MyPage.aspx and the web parts you added before won't appear. The workaround for this is to explicitly add web parts not within web part zones, and this can only be done in an authored page layout (usually in SharePoint Designer).
If the web parts are static in the page layout (and you want them to show in every page) then this is actually easier for you to deploy - just maintain the layout in your source, and have it provisioned via a Module element.
Finally I used another approach to reach my goal. In the OnLoad event of the provider webpart, I check if my page is in edit/new mode, and then check if the page contains the consumer webpart (via the webpartmanager) and if they are not already connected. If this is the case, I connect them.
The code to connect permanently the webparts:
private void SetUpConnections()
{
SPSecurity.RunWithElevatedPrivileges(delegate() {
using (SPSite siteContext = new SPSite(SPContext.Current.Site.ID))
using (SPWeb webContext = siteContext.OpenWeb(siteContext.ServerRelativeUrl))
using (SPLimitedWebPartManager spManager = webContext.GetFile(SPContext.Current.File.Url).GetLimitedWebPartManager(PersonalizationScope.Shared))
{
foreach (Microsoft.SharePoint.WebPartPages.WebPart consumer in spManager.WebParts)
{
if (consumer is MyConsumerWebPart)
{
bool alreadyConnected = false;
Microsoft.SharePoint.WebPartPages.WebPart provider = spManager.WebParts[this.ID] as Microsoft.SharePoint.WebPartPages.WebPart;
foreach (SPWebPartConnection connection in spManager.SPWebPartConnections)
{
if (connection.Provider == provider && connection.Consumer == consumer) { alreadyConnected = true; break; }
}
if (!alreadyConnected)
{
// Connects webparts permanently (but the page would need a reload to display the connection)
ProviderConnectionPoint providerConnectionPoint = spManager.GetProviderConnectionPoints(provider)["MyConnectionProviderInterfaceId"];
ConsumerConnectionPoint consumerConnectionPoint = spManager.GetConsumerConnectionPoints(consumer)["MyConnectionConsumerInterfaceId"];
spManager.SPConnectWebParts(provider, providerConnectionPoint, consumer, consumerConnectionPoint);
// Connects webparts locally (for current edit mode)
SPWebPartManager currentSPManager = WebPartManager.GetCurrentWebPartManager(this.Page) as SPWebPartManager;
System.Web.UI.WebControls.WebParts.WebPart currentProvider = this;
System.Web.UI.WebControls.WebParts.WebPart currentConsumer = currentSPManager.WebParts[consumer.ID];
ProviderConnectionPoint currentProviderConnectionPoint = currentSPManager.GetProviderConnectionPoints(currentProvider)["SearchBarProvider"];
ConsumerConnectionPoint currentConsumerConnectionPoint = currentSPManager.GetConsumerConnectionPoints(currentConsumer)["SearchBarConsumer"];
currentSPManager.SPConnectWebParts(currentProvider, currentProviderConnectionPoint, currentConsumer, currentConsumerConnectionPoint);
}
}
}
}
});
}
The code to check if the page is in new/edit mode:
if (SPContext.Current.FormContext.FormMode == SPControlMode.New
|| SPContext.Current.FormContext.FormMode == SPControlMode.Edit)
{
this.SetUpConnections();
}

Resources